diff --git a/README.md b/README.md index a2754de..b6b4663 100644 --- a/README.md +++ b/README.md @@ -1,124 +1,17 @@ # Project 5: Shaders -## Project Instructions +# Pointilism +I computed a random value based on the pixel position and scaled the random value by the darkness. If the probability was above a certain threshold, I made it dark. Otherwise, I made it light. -Implement at least 75 points worth of shaders from the following list. We reserve the right to grant only partial credit for shaders that do not meet our standards, as well as extra credit for shaders that we find to be particularly impressive. +# Gaussian +I hand calculated the weights for the neighboring pixels for the gaussian blur and used a sigma value of 1 and a kernel size of 3. -Some of these shading effects were covered in lecture -- some were not. If you wish to implement the more complex effects, you will have to perform some extra research. Of course, we encourage such academic curiosity which is why we’ve included these advanced shaders in the first place! +# Iridescent +Iridescent was similar to lambert, except that I read from a rainbow texture and used the dot product between the view vector and normal as the uv offset. -Document each shader you implement in your README with at least a sentence or two of explanation. Well-commented code will earn you many brownie (and probably sanity) points. +# Sobel +Sobel estimates the gradient magnitude at every pixel to detect edges. -If you use shadertoy or any materials as reference, please properly credit your sources in the README and on top of the shader file. Failing to do so will result in plagiarism and will significantly reduce your points. - -Examples: [https://cis700-procedural-graphics.github.io/Project5-Shaders/](https://cis700-procedural-graphics.github.io/Project5-Shaders/) - -### 15 points each: Instagram-like filters - -- Tone mapping: - - Linear (5 points) - - Reinhard (5 points) - - Filmic (5 points) -- Gaussian blur (no double counting with Bloom) -- Iridescence -- Pointilism -- Vignette -- Fish-eye bulge - -### 25 points each: -- Bloom -- Noise Warp -- Hatching -- Edge detection with Sobel filtering -- Lit Sphere ([paper](http://www.ppsloan.org/publications/LitSphere.pdf)) -- Uncharted 2 customizable filmic curve, following John Hable’s presetantion. - - Without Linear, Reinhard, filmic (10 points) - - With all of linear, Reinhard, filmic (10 points) - - Customizable via GUI: (5 points total) - - Controlling Exposure - - Side by side comparison between linear, Reinhard, filmic, and Uncharted2 . - -### 37.5 points each: -- K-means color compression (unless you are extremely clever, the k-means clusterer has to be CPU side) -- Dithering - - -### 5 points - Interactivity -Implement a dropdown GUI to select different shader effects from your list. - -### ??? points -Propose your own shading effects! - -### For the overachievers: -Weave all your shading effects into one aesthetically-coherent scene, perhaps by incorporating some of your previous assignments! - - -## Getting Started - -### main.js - -`main.js` is responsible for setting up the scene with the Mario mesh, initializing GUI and camera, etc. - -### Adding Shaders - -To add a shader, you'll want to add a file to the `src/shaders` or `src/post` folder. As examples, we've provided two shaders `lambert.js` and `grayscale.js`. Here, I will give a brief overview of how these work and how everything hooks together. - -**shaders/lambert.js** - -IMPORTANT: I make my lambert shader available by exporting it in `shaders/index.js`. - -```javascript -export {default as Lambert} from './Lambert' -``` - -Each shader should export a function that takes in the `renderer`, `scene`, and `camera`. That function should return a `Shader` Object. - -`Shader.initGUI` is a function that will be called to initialize the GUI for that shader. in `lambert.js`, you can see that it's here that I set up all the parameters that will affect my shader. - -`Shader.material` should be a `THREE.ShaderMaterial`. This should be pretty similar to what you've seen in previous projects. `Shader.material.vertexShader` and `Shader.material.fragmentShader` are the vertex and fragment shaders used. - -At the bottom, I have the following snippet of code. All it does is bind the Mario texture once it's loaded. - -```javascript -textureLoaded.then(function(texture) { - Shader.material.uniforms.texture.value = texture; -}); -``` - -So when you change the Shader parameter in the GUI, `Shader.initGUI(gui)` will be called to initialize the GUI, and then the Mario mesh will have `Shader.material` applied to it. - -**post/grayscale.js** - -GUI parameters here are initialized the same way they are for the other shaders. - -Post process shaders should use the THREE.js `EffectComposer`. To set up the grayscale filter, I first create a new composer: `var composer = new EffectComposer(renderer);`. Then I add a a render pass as the first pass: `composer.addPass(new EffectComposer.RenderPass(scene, camera));`. This will set up the composer to render the scene as normal into a buffer. I add my filter to operate on that buffer: `composer.addPass(GrayscaleShader);`, and mark it as the final pass that will write to the screen `GrayscaleShader.renderToScreen = true;` - -GrayscaleShader is a `EffectComposer.ShaderPass` which basically takes the same arguments as `THREE.ShaderMaterial`. Note, that one uniform that will have to include is `tDiffuse`. This is the texture sampler which the EffectComposer will automatically bind the previously rendered pass to. If you look at `glsl/grayscale-frag.glsl`, this is the texture we read from to get the previous pixel color: `vec4 col = texture2D(tDiffuse, f_uv);`. - -IMPORTANT: You initially define your shader passes like so: - -```javascript -var GrayscaleShader = new EffectComposer.ShaderPass({ - uniforms: { - tDiffuse: { - type: 't', - value: null - }, - u_amount: { - type: 'f', - value: options.amount - } - }, - vertexShader: require('../glsl/pass-vert.glsl'), - fragmentShader: require('../glsl/grayscale-frag.glsl') -}); -``` - -BUT, if you want to modify the uniforms, you need to do so like so: `GrayscaleShader.material.uniforms.u_amount.value = val;`. Note the extra `.material` property. - -## Deploy - -1. Create a `gh-pages` branch on GitHub -2. Do `npm run build` -3. Commit and add all your changes. -4. Do `npm run deploy` \ No newline at end of file +# Vignette +I did a linear interpolation between a gui variable color and the pixel color. I used the distance to the center as a t value. \ No newline at end of file diff --git a/build/assets/iridescent-ec82e7.bmp b/build/assets/iridescent-ec82e7.bmp new file mode 100644 index 0000000..2f399a0 Binary files /dev/null and b/build/assets/iridescent-ec82e7.bmp differ diff --git a/build/assets/wahoo-1bfe66.bmp b/build/assets/wahoo-1bfe66.bmp new file mode 100644 index 0000000..bf1598d Binary files /dev/null and b/build/assets/wahoo-1bfe66.bmp differ diff --git a/build/assets/wahoo-d362db.obj b/build/assets/wahoo-d362db.obj new file mode 100644 index 0000000..ada73fa --- /dev/null +++ b/build/assets/wahoo-d362db.obj @@ -0,0 +1,19990 @@ +# This file uses centimeters as units for non-parametric coordinates. + +mtllib wahoo.mtl +g default +v -2.216943 12.923250 0.119637 +v -2.195156 12.285880 0.337008 +v -2.146946 12.233870 0.057483 +v -2.139170 11.805940 0.285713 +v -1.983671 11.835360 0.236490 +v -2.130655 11.591450 0.364777 +v -1.949520 11.528890 0.259314 +v -2.054907 11.208260 0.371858 +v -1.945046 11.440840 0.923296 +v -2.001590 11.243500 0.916731 +v -2.182530 11.299400 0.877241 +v -2.022460 11.111590 0.782854 +v -2.214451 11.214820 0.774437 +v -2.098189 11.093460 0.566006 +v -2.226095 11.208140 0.613458 +v -2.184353 11.296510 0.474390 +v -2.248510 11.413730 0.670896 +v -2.196206 11.665280 0.577699 +v -2.124498 11.487390 0.894370 +v -2.107205 11.708750 0.778702 +v -1.875545 11.678560 0.768814 +v -1.907583 11.543470 0.854359 +v -1.846983 11.552890 1.096587 +v -2.015492 11.621320 1.073624 +v -1.981454 11.760270 1.170597 +v -2.104143 11.792260 0.954896 +v -1.963534 11.950640 1.162370 +v -2.014652 12.158610 0.929041 +v -1.777757 11.955300 1.200662 +v -1.854854 12.154090 0.975477 +v 2.216945 12.923250 0.119637 +v 2.146948 12.233870 0.057483 +v 2.195158 12.285880 0.337008 +v 2.139171 11.805940 0.285713 +v 2.176097 11.887930 0.475155 +v 2.196207 11.665280 0.577699 +v 2.160163 11.940740 0.650208 +v 2.107207 11.708750 0.778702 +v 2.104145 11.792260 0.954896 +v 2.045211 11.625520 0.876442 +v 2.015493 11.621320 1.073624 +v 1.907585 11.543470 0.854359 +v 1.846984 11.552890 1.096587 +v 1.875547 11.678560 0.768814 +v 1.765980 11.722780 1.214066 +v 1.777759 11.955300 1.200662 +v 1.981455 11.760260 1.170597 +v 1.963535 11.950640 1.162370 +v 2.014654 12.158610 0.929041 +v 2.127965 12.042350 0.788983 +v 2.033085 12.463900 0.836395 +v 2.142205 12.393590 0.651243 +v 2.129809 12.880170 0.614464 +v 1.983672 11.835360 0.236490 +v 2.130656 11.591450 0.364777 +v 2.184354 11.296510 0.474390 +v 2.248512 11.413730 0.670896 +v 2.226096 11.208140 0.613458 +v 2.214452 11.214820 0.774437 +v 2.098190 11.093460 0.566006 +v 2.022461 11.111590 0.782854 +v 2.001591 11.243500 0.916731 +v 2.182531 11.299410 0.877241 +v 1.945047 11.440840 0.923295 +v 2.124499 11.487390 0.894370 +v 0.173954 9.940690 -0.762887 +v 0.000000 10.091340 -1.190654 +v -0.173954 9.940691 -0.762887 +v -0.331883 10.113470 -1.832893 +v -0.600183 10.020360 -1.750984 +v -0.661912 10.331430 -2.029534 +v -0.880795 10.187230 -1.685436 +v -0.904461 10.471080 -1.847084 +v -0.968637 10.652000 -1.282741 +v -0.806184 10.791520 -1.604582 +v -1.302291 10.891090 -1.311605 +v -1.444652 11.412730 -1.511187 +v -1.891213 11.562660 -1.073484 +v -2.004606 12.324450 -0.938761 +v -1.998260 11.610960 -0.654074 +v -2.111865 12.093770 -0.533781 +v -0.500968 9.962947 -0.709236 +v -0.865765 10.278760 -1.020668 +v -1.443211 10.278860 -1.392483 +v -1.458136 10.628360 -1.496472 +v -1.791096 10.539920 -1.446361 +v -1.697228 10.791760 -1.364097 +v -1.825185 10.675360 -1.111651 +v -1.696256 11.045740 -0.984049 +v -1.684370 10.816370 -0.747007 +v -1.865378 11.267420 -0.596922 +v -1.764854 10.938110 -0.323067 +v -0.762570 13.133470 -1.794380 +v -0.850897 12.910430 -1.894065 +v 0.000000 13.133470 -1.960311 +v 0.000000 12.924100 -2.050328 +v 0.850898 12.910430 -1.894065 +v 0.856521 12.414240 -1.977031 +v 1.554018 12.875220 -1.491075 +v 1.564146 12.377970 -1.560276 +v 2.050779 13.008110 -0.856171 +v 2.004607 12.324450 -0.938761 +v 2.216049 12.947910 -0.164166 +v 2.142157 12.178580 -0.242920 +v 0.880797 10.187230 -1.685436 +v 0.865766 10.278760 -1.020669 +v 0.968638 10.652000 -1.282742 +v 1.443212 10.278860 -1.392483 +v 1.458137 10.628360 -1.496472 +v 1.791097 10.539920 -1.446361 +v 1.697229 10.791760 -1.364096 +v 1.825187 10.675360 -1.111650 +v 1.696257 11.045740 -0.984049 +v 1.684371 10.816370 -0.747007 +v 1.865379 11.267420 -0.596922 +v 1.764855 10.938110 -0.323067 +v 0.500968 9.962948 -0.709236 +v 0.600185 10.020360 -1.750984 +v 0.331885 10.113470 -1.832893 +v 0.000000 10.441960 -1.504729 +v -0.356751 10.430160 -1.997718 +v -0.654210 10.597500 -1.999283 +v 0.283725 10.772610 -1.777112 +v 0.356752 10.430160 -1.997718 +v 0.661913 10.331430 -2.029534 +v 0.815985 10.062070 -0.626377 +v 1.136659 10.241760 -0.507994 +v 0.904463 10.471090 -1.847084 +v 0.806185 10.791520 -1.604583 +v 1.302292 10.891090 -1.311605 +v 1.444654 11.412730 -1.511187 +v 1.891214 11.562660 -1.073484 +v 1.998262 11.610960 -0.654074 +v -2.216048 12.947920 -0.164166 +v -2.136702 13.566260 -0.078035 +v -2.049804 13.482330 0.881773 +v -2.129808 12.880180 0.614464 +v -1.992681 12.899080 0.975527 +v -2.024144 12.710680 0.869038 +v -1.849790 12.707070 0.908197 +v -1.851952 12.460420 0.873226 +v 2.049805 13.482330 0.881773 +v 1.992682 12.899080 0.975527 +v 1.879542 13.449680 1.254955 +v 1.902320 13.059110 1.227250 +v 1.754212 13.248900 1.414334 +v 1.752323 12.986150 1.243370 +v 1.669672 13.197120 1.405103 +v -2.176095 11.887930 0.475155 +v -2.160162 11.940740 0.650208 +v 1.848828 12.847500 1.007644 +v 1.849792 12.707060 0.908197 +v 2.024145 12.710680 0.869038 +v 1.851954 12.460410 0.873226 +v 1.854856 12.154090 0.975477 +v -1.879540 13.449680 1.254955 +v -1.902319 13.059110 1.227250 +v -1.752321 12.986150 1.243370 +v -1.754210 13.248900 1.414333 +v -1.669671 13.197120 1.405103 +v -1.540265 13.429660 1.483626 +v -1.564145 12.377970 -1.560276 +v -0.876577 11.322070 -1.850234 +v -0.856520 12.414240 -1.977031 +v 0.000000 11.283440 -2.027815 +v 0.000000 12.428850 -2.144014 +v 1.458574 10.519830 -0.414324 +v 1.771773 10.338560 -0.987523 +v 1.631313 10.215990 -1.217332 +v -2.142203 12.393590 0.651243 +v -2.127963 12.042350 0.788983 +v 0.876578 11.322070 -1.850234 +v 2.136703 13.566260 -0.078035 +v 1.980016 13.312200 -0.673932 +v 1.464660 13.125420 -1.262647 +v -2.142156 12.178580 -0.242920 +v -2.050777 13.008110 -0.856171 +v -1.980015 13.312200 -0.673932 +v -2.045209 11.625520 0.876442 +v -1.458574 10.519830 -0.414324 +v -1.771772 10.338560 -0.987523 +v -1.136659 10.241760 -0.507994 +v -1.631312 10.215990 -1.217332 +v 2.054909 11.208260 0.371858 +v 1.949521 11.528890 0.259314 +v -1.554017 12.875220 -1.491076 +v -1.464659 13.125420 -1.262648 +v -1.765979 11.722780 1.214066 +v -2.033083 12.463900 0.836395 +v 0.654211 10.597500 -1.999283 +v -0.283723 10.772610 -1.777111 +v 2.111866 12.093770 -0.533781 +v -1.848827 12.847500 1.007644 +v 0.762571 13.133470 -1.794380 +v 1.540266 13.429660 1.483626 +v -0.815985 10.062070 -0.626377 +v -2.249846 8.996571 -1.016292 +v -2.095228 8.942923 -0.982662 +v -2.274166 9.323943 -0.732976 +v -2.092406 9.295671 -0.688096 +v -2.274351 9.477137 -0.252395 +v -2.099802 9.431505 -0.237113 +v -2.274092 9.409076 0.216789 +v -2.091646 9.352252 0.221695 +v -2.236557 9.067966 0.533070 +v -2.069095 9.037211 0.546545 +v -2.451334 9.261692 -0.680461 +v -2.452020 9.377912 -0.250958 +v -2.447641 9.310001 0.184659 +v -2.404116 9.048821 0.475579 +v 2.019257 8.533868 0.564041 +v 2.152578 8.572943 0.532946 +v 2.084343 8.219757 0.333510 +v 2.281664 8.590114 0.505553 +v 2.415061 8.245862 0.318178 +v 2.579731 8.608575 0.544145 +v 3.276448 8.257201 0.290141 +v 3.230914 8.631798 0.481535 +v 2.097742 8.063627 -0.136605 +v 3.293915 8.110773 -0.122855 +v 3.251055 8.167455 -0.552296 +v 2.096345 8.126066 -0.651799 +v 2.372117 8.924417 -0.938670 +v 2.789803 9.266207 -0.695358 +v 2.451334 9.261692 -0.680461 +v 2.791202 9.444347 -0.258526 +v 2.452020 9.377912 -0.250958 +v 2.780204 9.357681 0.208431 +v 2.447641 9.310001 0.184659 +v 2.738098 9.083788 0.502150 +v 2.404116 9.048821 0.475579 +v 3.184967 8.481375 -0.835483 +v 2.513854 8.444242 -0.896062 +v 2.167635 8.416526 -0.900271 +v 2.741734 8.941839 -0.954005 +v 2.236557 9.067966 0.533070 +v 2.249846 8.996571 -1.016292 +v 3.140581 8.905190 -0.877426 +v -3.293916 8.110772 -0.122855 +v -3.459762 8.075050 -0.114235 +v -3.276449 8.257200 0.290141 +v -3.438980 8.221250 0.312939 +v -3.230914 8.631797 0.481535 +v -3.393072 8.659723 0.529067 +v -3.210542 9.046826 0.439702 +v -3.370332 9.114877 0.476921 +v -3.196370 9.304530 0.166887 +v -3.359460 9.403924 0.159260 +v -3.174461 9.378980 -0.248478 +v -3.352812 9.480322 -0.255854 +v -3.141653 9.213829 -0.631361 +v -3.346468 9.311706 -0.653676 +v -3.140581 8.905189 -0.877425 +v -3.346888 8.957955 -0.912052 +v -3.184967 8.481375 -0.835482 +v -3.377712 8.494865 -0.869280 +v -3.251055 8.167454 -0.552295 +v -3.464180 8.129780 -0.554064 +v -3.581581 8.131690 -0.116597 +v -3.553064 8.273570 0.277314 +v -3.502109 8.658823 0.465555 +v -3.503856 9.088876 0.411167 +v -3.503825 9.339264 0.132956 +v -3.504467 9.418930 -0.249171 +v -3.500406 9.255958 -0.611162 +v -3.658715 9.313344 -0.632411 +v -3.684639 8.939346 -0.918072 +v -3.871223 9.227571 -0.604144 +v -3.905590 8.930397 -0.826882 +v -5.135573 9.247667 -0.642477 +v -5.135573 8.946057 -0.850693 +v -5.135573 9.395838 -0.296076 +v -3.866405 9.385774 -0.256778 +v -5.135573 9.329805 0.052068 +v -3.850333 9.308563 0.118534 +v -5.135573 9.081923 0.319171 +v -3.828467 9.061715 0.396197 +v -5.135573 8.626042 0.394023 +v -3.793335 8.651396 0.457404 +v -5.135573 8.292844 0.177373 +v -3.847551 8.271982 0.258346 +v -5.135573 8.166908 -0.189749 +v -3.878393 8.127088 -0.130897 +v -3.651528 9.475913 -0.254629 +v -3.641679 9.399603 0.143062 +v -3.624684 9.091155 0.451490 +v -3.609709 8.659945 0.511600 +v -3.687481 8.222446 0.297035 +v -3.728814 8.084153 -0.115576 +v -2.579731 8.608574 0.544146 +v -2.738098 9.083787 0.502150 +v -2.780204 9.357680 0.208432 +v -2.791202 9.444347 -0.258526 +v -2.789803 9.266207 -0.695358 +v -2.741734 8.941838 -0.954005 +v -5.135573 8.210233 -0.594810 +v -3.896259 8.177543 -0.540723 +v -5.135573 8.476259 -0.818881 +v -3.883728 8.510544 -0.802117 +v -3.728101 8.126244 -0.554214 +v -3.687643 8.494137 -0.892054 +v -3.501694 8.512317 -0.799257 +v -3.498593 8.949540 -0.839325 +v -3.571227 8.174915 -0.531879 +v 0.328428 10.189790 -0.686949 +v 0.000000 10.196580 -0.741730 +v 0.000000 9.889837 -0.758413 +v -0.328428 10.189790 -0.686949 +v -0.306755 9.889966 -0.706201 +v -0.572056 10.190650 -0.405879 +v -0.550606 9.892770 -0.431475 +v -0.689986 10.197590 -0.046287 +v -0.664180 9.894575 -0.087160 +v -0.695253 10.161060 0.294091 +v -0.669233 9.858460 0.254776 +v -0.455517 10.061210 0.643135 +v -0.438332 9.769849 0.577070 +v 0.000000 10.015260 0.772229 +v 0.000000 9.726416 0.673848 +v 0.438332 9.769849 0.577070 +v 0.469978 9.460013 0.641627 +v 0.710580 9.705617 0.303900 +v 0.572056 10.190650 -0.405879 +v 0.306755 9.889966 -0.706201 +v 0.000000 9.671125 -0.780808 +v -0.330569 9.679994 -0.734733 +v -0.582157 9.725809 -0.490976 +v -0.706396 9.698792 -0.087989 +v -0.710580 9.705617 0.303900 +v -0.469978 9.460013 0.641627 +v 0.000000 9.394969 0.750135 +v 0.667052 9.829982 -0.622190 +v 0.416284 9.832101 -0.902593 +v 0.418515 9.584204 -0.950069 +v 0.000000 9.831134 -0.956613 +v 0.000000 9.574591 -1.005139 +v -0.418515 9.584204 -0.950069 +v -0.424175 9.503987 -0.946899 +v -0.622645 9.508775 -0.882633 +v 0.000000 9.416018 0.971834 +v -0.466110 9.479513 0.832658 +v -0.466571 9.649618 0.766703 +v -0.815733 9.586674 0.510893 +v -0.766278 9.775494 0.335621 +v -0.803529 9.622688 0.283393 +v -0.763946 9.657425 -0.151422 +v 0.693376 9.664098 -0.617521 +v 0.663240 9.599764 -0.757944 +v 0.622645 9.508775 -0.882633 +v 0.424175 9.503987 -0.946899 +v 0.762696 9.829117 -0.119605 +v 0.582157 9.725809 -0.490976 +v 0.330569 9.679994 -0.734733 +v 0.766278 9.775494 0.335621 +v 0.466571 9.649618 0.766703 +v 0.000000 9.584548 0.908440 +v -0.762696 9.829117 -0.119605 +v -0.667052 9.829982 -0.622190 +v -0.416284 9.832101 -0.902593 +v 0.455517 10.061210 0.643135 +v 0.669233 9.858460 0.254776 +v 0.706396 9.698792 -0.087989 +v 0.695253 10.161060 0.294091 +v 0.664180 9.894575 -0.087160 +v 0.689986 10.197590 -0.046287 +v 0.550606 9.892770 -0.431475 +v 0.763946 9.657425 -0.151422 +v 0.803529 9.622688 0.283393 +v 0.815733 9.586674 0.510893 +v 0.466110 9.479513 0.832658 +v -0.693376 9.664098 -0.617521 +v -0.663240 9.599764 -0.757944 +v 0.000000 9.494684 -1.010764 +v 2.274166 9.323943 -0.732976 +v 2.095228 8.942923 -0.982662 +v 2.092406 9.295671 -0.688096 +v 2.091646 9.352252 0.221695 +v 2.099802 9.431505 -0.237113 +v 2.274092 9.409076 0.216789 +v 2.274351 9.477137 -0.252395 +v 1.802249 9.049370 0.606047 +v 1.935672 9.043290 0.576296 +v 2.069095 9.037211 0.546545 +v 1.969509 9.409927 0.249923 +v 1.974017 9.006832 -1.011963 +v 1.970519 9.371658 -0.707210 +v 1.974219 9.497014 -0.227655 +v -1.564361 8.917301 0.920245 +v -1.802249 9.049370 0.606047 +v -1.466578 9.356601 0.474635 +v -1.755165 9.332519 0.278150 +v -1.389311 9.530473 -0.071460 +v -1.756431 9.427438 -0.218198 +v -1.339691 9.514383 -0.476317 +v -1.756426 9.312563 -0.726324 +v -1.285743 9.349880 -0.929480 +v -1.788147 9.070743 -1.041265 +v -1.244225 8.825111 -1.284364 +v 0.817863 9.416183 0.798099 +v 0.465124 9.315750 1.036134 +v 0.000000 9.261077 1.140214 +v -0.465124 9.315750 1.036134 +v -0.465458 9.234077 1.048366 +v -0.829620 9.340392 0.844160 +v -0.829135 9.228011 1.075755 +v 0.829620 9.340392 0.844160 +v 0.465458 9.234077 1.048366 +v 0.000000 9.170037 1.144692 +v -0.491632 9.130054 1.259296 +v -0.831524 9.088048 1.112448 +v 1.244225 8.825111 -1.284364 +v 1.788147 9.070743 -1.041265 +v 1.285743 9.349880 -0.929480 +v 1.756426 9.312563 -0.726324 +v 1.339691 9.514383 -0.476317 +v 1.756431 9.427438 -0.218198 +v 1.389311 9.530473 -0.071460 +v 1.755165 9.332519 0.278150 +v 1.466578 9.356601 0.474635 +v 0.829135 9.228011 1.075755 +v 0.491632 9.130054 1.259296 +v 0.000000 9.063251 1.339907 +v 0.397697 9.115714 -1.273372 +v 0.000000 9.140750 -1.319746 +v -0.397697 9.115714 -1.273372 +v -0.489355 8.992829 1.296504 +v 0.000000 8.937310 1.393471 +v 0.489355 8.992829 1.296504 +v 0.831524 9.088048 1.112448 +v -0.817863 9.416183 0.798099 +v 1.564361 8.917301 0.920245 +v 5.135574 8.946058 -0.850694 +v 5.135574 9.247668 -0.642478 +v 3.905590 8.930397 -0.826882 +v 3.871223 9.227571 -0.604145 +v 3.684639 8.939346 -0.918072 +v 3.658715 9.313344 -0.632411 +v 3.500406 9.255958 -0.611162 +v 3.504467 9.418930 -0.249171 +v 3.352812 9.480322 -0.255854 +v 3.503825 9.339264 0.132956 +v 3.359460 9.403924 0.159260 +v 3.503856 9.088876 0.411167 +v 3.370332 9.114877 0.476921 +v 3.502109 8.658823 0.465555 +v 3.393072 8.659723 0.529067 +v 3.553064 8.273570 0.277314 +v 3.438980 8.221250 0.312939 +v 3.581581 8.131690 -0.116597 +v 3.459762 8.075050 -0.114235 +v 5.135573 8.166909 -0.189749 +v 5.135573 8.210232 -0.594811 +v 3.878393 8.127088 -0.130898 +v 3.896260 8.177542 -0.540723 +v 3.728814 8.084154 -0.115577 +v 3.728101 8.126244 -0.554214 +v 3.571227 8.174915 -0.531879 +v 3.687643 8.494137 -0.892054 +v 3.501694 8.512317 -0.799257 +v 3.498593 8.949540 -0.839325 +v 3.346888 8.957955 -0.912052 +v 3.346468 9.311706 -0.653676 +v 3.141652 9.213830 -0.631361 +v 5.135574 9.329806 0.052067 +v 5.135574 9.081924 0.319170 +v 3.850333 9.308564 0.118533 +v 3.828467 9.061716 0.396196 +v 3.641679 9.399603 0.143062 +v 3.624684 9.091155 0.451489 +v 3.609709 8.659946 0.511599 +v 3.687481 8.222446 0.297035 +v 5.135574 9.395837 -0.296076 +v 3.866406 9.385774 -0.256779 +v 3.651528 9.475913 -0.254629 +v 5.135574 8.292843 0.177372 +v 3.847551 8.271983 0.258346 +v 3.174461 9.378980 -0.248479 +v 3.464180 8.129779 -0.554064 +v 5.135574 8.476260 -0.818882 +v 3.883728 8.510543 -0.802117 +v 5.135574 8.626043 0.394022 +v 3.793336 8.651395 0.457404 +v 3.210541 9.046826 0.439701 +v 3.196370 9.304531 0.166886 +v 3.377712 8.494865 -0.869280 +v 0.000000 8.641103 -1.553166 +v 0.833126 8.957104 1.302518 +v 0.488965 8.841544 1.487280 +v 0.000000 8.790028 1.545348 +v -0.488965 8.841544 1.487280 +v 0.000000 8.126963 1.966566 +v -0.546090 8.180715 1.880842 +v 1.926530 8.447002 0.701776 +v 1.911774 8.378123 0.925387 +v 1.691858 8.094415 1.434244 +v -0.831977 8.249213 1.795377 +v -0.833126 8.957104 1.302518 +v 0.546090 8.180715 1.880842 +v 0.831977 8.249213 1.795377 +v -2.075356 7.331665 -0.331779 +v -2.203938 7.649073 -0.236173 +v -2.098186 7.367910 0.188199 +v -2.213226 7.725855 0.287209 +v -1.954920 7.633939 1.121605 +v -2.116142 7.906538 0.699553 +v -1.691858 8.094415 1.434244 +v -1.911774 8.378123 0.925387 +v -2.066470 7.827462 -0.211844 +v -2.033270 7.924818 -0.741326 +v -2.108718 7.741127 -0.783490 +v -1.799843 8.085003 -1.137551 +v -1.585619 7.635220 -1.223837 +v -2.036919 8.053317 0.495236 +v -2.064526 7.926696 0.290517 +v -1.903092 7.416755 -0.895911 +v -1.926530 8.447002 0.701776 +v -2.071481 7.453075 0.639595 +v -2.032541 8.441614 -0.964535 +v -2.055957 8.123894 -0.653327 +v -2.057459 8.061687 -0.136998 +v -2.152578 8.572943 0.532946 +v -2.019257 8.533868 0.564041 +v -2.084343 8.219757 0.333510 +v -2.044459 8.218604 0.333439 +v -2.167635 8.416526 -0.900271 +v -2.096345 8.126066 -0.651799 +v -2.097742 8.063627 -0.136605 +v -2.372117 8.924417 -0.938670 +v -2.513854 8.444242 -0.896062 +v -2.281664 8.590114 0.505553 +v -2.415061 8.245862 0.318178 +v 2.057459 8.061687 -0.136998 +v 2.044459 8.218604 0.333439 +v 2.036919 8.053317 0.495236 +v 2.064526 7.926696 0.290517 +v 2.066470 7.827462 -0.211844 +v 2.055957 8.123894 -0.653327 +v 2.033270 7.924818 -0.741326 +v 2.075356 7.331665 -0.331779 +v 2.098186 7.367910 0.188199 +v 2.203938 7.649073 -0.236173 +v 2.213226 7.725855 0.287209 +v 2.108718 7.741127 -0.783490 +v 1.903092 7.416755 -0.895911 +v 2.116142 7.906538 0.699553 +v 1.954920 7.633939 1.121605 +v 2.071481 7.453075 0.639595 +v 1.799843 8.085003 -1.137551 +v 1.585619 7.635220 -1.223837 +v -1.819740 8.545136 -1.102408 +v -1.352945 8.267432 -1.400377 +v 1.352945 8.267432 -1.400377 +v 1.819740 8.545136 -1.102408 +v -1.974017 9.006832 -1.011963 +v -1.970519 9.371658 -0.707210 +v -1.974219 9.497014 -0.227655 +v -1.969509 9.409927 0.249923 +v -1.935672 9.043290 0.576296 +v 2.032541 8.441614 -0.964535 +v -8.179667 9.314501 -0.639025 +v -8.179556 9.360185 -0.430256 +v -8.216846 9.123878 -0.503844 +v -8.044007 8.991931 -0.348752 +v -8.033488 8.875973 -0.463723 +v -7.756835 8.964725 -0.304101 +v -7.773302 8.823855 -0.451987 +v -7.347109 8.975100 -0.307279 +v -7.342510 8.829979 -0.445761 +v -6.817776 8.754169 -0.430131 +v -6.780320 8.858657 -0.657140 +v -8.309417 9.408785 -0.194006 +v -8.312749 9.417867 0.035640 +v -8.314708 9.178495 -0.061269 +v -8.121567 9.030010 0.135722 +v -8.134691 8.946482 -0.046379 +v -7.836949 8.986316 0.153544 +v -7.852835 8.884460 -0.046134 +v -7.398368 8.963253 0.130058 +v -7.396554 8.865445 -0.049803 +v -6.841866 8.797432 -0.034164 +v -6.855141 8.934999 -0.267219 +v -8.112272 9.380780 -0.336061 +v -7.841775 9.416004 -0.538719 +v -7.810649 9.382998 -0.292276 +v -7.474546 9.421888 -0.538703 +v -7.458974 9.358718 -0.305856 +v -7.382454 9.426131 -0.541293 +v -7.372396 9.372733 -0.307057 +v -6.962314 9.485083 -0.546023 +v -6.840041 9.503675 -0.319305 +v -6.816284 9.603395 -0.545406 +v -8.203904 9.418514 0.155648 +v -7.925027 9.486909 -0.088351 +v -7.888582 9.394939 0.179238 +v -7.518940 9.493416 -0.092176 +v -7.507607 9.353236 0.152010 +v -7.426172 9.490963 -0.092085 +v -7.414294 9.362523 0.154874 +v -7.002219 9.536085 -0.089993 +v -6.813945 9.462174 0.165748 +v -6.840199 9.653583 -0.094609 +v -8.212494 9.414017 -0.310114 +v -7.887812 9.395960 -0.336687 +v -7.511127 9.376824 -0.311996 +v -7.404203 9.377500 -0.312259 +v -6.766116 9.361799 -0.750882 +v -7.343761 9.277565 -0.723250 +v -7.447306 9.267234 -0.718223 +v -8.038750 8.946249 -0.636593 +v -7.748329 8.907350 -0.659378 +v -8.087164 9.293324 -0.735649 +v -7.798517 9.278990 -0.757805 +v -7.340391 8.917072 -0.643713 +v -8.118916 9.013198 -0.240437 +v -7.830240 8.979107 -0.266180 +v -7.396997 8.974938 -0.251265 +v -6.828564 8.948879 0.168619 +v -7.364922 8.842179 0.362677 +v -6.801849 8.768546 0.384919 +v -7.361333 8.928006 0.577168 +v -6.775223 8.944337 0.629420 +v -6.774453 9.332331 0.618401 +v -7.370883 9.285694 0.619367 +v -6.961171 9.461555 0.388416 +v -6.813742 9.567743 0.374199 +v -7.382149 9.374517 0.187496 +v -7.370904 8.965876 0.190424 +v -7.393486 9.399494 0.386852 +v -6.571239 8.845072 0.660922 +v -6.308940 8.942182 0.839121 +v -6.840092 8.707955 0.674622 +v -6.722010 8.769037 1.029889 +v -7.102796 8.785803 0.970555 +v -7.158222 8.525596 1.096398 +v -7.474892 8.520159 1.096025 +v -7.362446 8.255560 1.011993 +v -7.472131 8.504058 0.856924 +v -7.342676 8.258613 0.740244 +v -7.323744 8.464378 0.611797 +v -7.130948 8.210620 0.686298 +v -7.119767 8.464377 0.559010 +v -6.840899 8.249853 0.705505 +v -6.811357 8.471261 0.587308 +v -6.437701 8.458210 0.358747 +v -5.880557 8.025977 0.563839 +v -6.248789 8.041136 0.823664 +v -5.749849 8.193149 0.823555 +v -6.177991 8.197435 1.075377 +v -5.708314 8.528291 0.916221 +v -6.160355 8.527845 1.153063 +v -5.756501 8.879025 0.785507 +v -6.203051 8.859719 1.028546 +v -7.124812 8.717811 0.644927 +v -7.354870 8.763052 0.977158 +v -6.717686 8.240335 1.072672 +v -7.132930 8.212913 1.013866 +v -6.398507 9.245222 0.716288 +v -6.350201 8.109765 0.578347 +v -6.028211 8.074326 0.276072 +v -7.335336 8.689917 0.695687 +v -6.723957 8.527247 1.155483 +v -6.398215 9.449624 0.554759 +v -5.759155 9.243464 0.593573 +v -6.321032 9.627040 0.264155 +v -6.166216 9.661923 0.247118 +v -6.176432 9.597869 0.277498 +v -6.073654 9.649300 0.221229 +v -6.035813 9.579247 0.234994 +v -6.037639 9.650229 0.177893 +v -5.981553 9.582085 0.161539 +v -6.079271 9.664174 0.142496 +v -6.045433 9.604718 0.100165 +v -6.174158 9.682962 0.135771 +v -6.190035 9.633893 0.086822 +v -6.266725 9.695587 0.161660 +v -6.330651 9.652513 0.129326 +v -6.302738 9.694654 0.204997 +v -6.384912 9.649673 0.202780 +v -6.261107 9.680712 0.240395 +v -6.327708 9.565610 -0.735443 +v -6.172019 9.597438 -0.749478 +v -6.186669 9.560635 -0.690629 +v -6.076698 9.579829 -0.752284 +v -6.041400 9.532553 -0.697795 +v -6.034742 9.559041 -0.783800 +v -5.976995 9.497819 -0.752744 +v -6.070733 9.547254 -0.825565 +v -6.031186 9.476773 -0.823287 +v -6.163582 9.551372 -0.853115 +v -6.172222 9.481747 -0.868100 +v -6.258902 9.568978 -0.850309 +v -6.317491 9.509827 -0.860934 +v -6.300855 9.589767 -0.818792 +v -6.381896 9.544565 -0.805986 +v -6.264869 9.601554 -0.777028 +v -6.335401 9.686331 -0.243604 +v -6.181599 9.727705 -0.255999 +v -6.191704 9.674239 -0.210001 +v -6.086267 9.715934 -0.269034 +v -6.046574 9.655986 -0.232991 +v -6.045944 9.707458 -0.307482 +v -5.985027 9.642262 -0.299105 +v -6.084248 9.707248 -0.348817 +v -6.043116 9.641109 -0.369615 +v -6.178743 9.715421 -0.368828 +v -6.186815 9.653203 -0.403217 +v -6.274076 9.727193 -0.355792 +v -6.331943 9.671457 -0.380227 +v -6.314402 9.735666 -0.317346 +v -6.393492 9.685179 -0.314113 +v -6.276094 9.735878 -0.276009 +v -6.733444 8.646387 -0.818458 +v -6.368999 8.420352 -0.887948 +v -6.686448 8.797213 -1.063444 +v -6.368480 8.653156 -1.115953 +v -6.661691 9.117439 -1.179774 +v -6.379900 9.087399 -1.202902 +v -6.391321 9.336958 -1.132230 +v -5.755214 9.048764 -1.120826 +v -5.758732 9.415091 -0.906099 +v -5.346496 9.027624 -0.901556 +v -5.332999 9.362614 -0.732852 +v -5.241756 9.075201 -1.051953 +v -5.241756 9.447242 -0.777776 +v -5.016000 9.071982 -1.083922 +v -5.016000 9.461335 -0.797986 +v -4.906000 9.072750 -0.976055 +v -4.906000 9.385557 -0.729061 +v -6.369055 8.300657 -0.431480 +v -5.745581 8.288541 -0.819154 +v -5.751696 8.602971 -1.059812 +v -5.346607 8.374742 -0.787549 +v -5.346349 8.631769 -0.952315 +v -5.241756 8.237027 -0.920327 +v -5.241756 8.622484 -1.076169 +v -5.016000 8.206284 -0.945124 +v -5.016000 8.616241 -1.110397 +v -4.906000 8.320722 -0.862616 +v -4.906000 8.668270 -1.001493 +v -6.160312 8.300775 -0.008148 +v -5.745901 8.139384 -0.416817 +v -5.347149 8.216182 -0.537451 +v -5.241756 8.021845 -0.596906 +v -5.016000 7.989539 -0.609757 +v -4.906000 8.098461 -0.577437 +v -5.509262 8.688493 0.739440 +v -5.348994 8.399103 0.523214 +v -5.348429 8.228843 0.268001 +v -5.347767 8.129204 -0.101954 +v -6.430676 9.669760 -0.555716 +v -6.406479 9.481427 -0.959756 +v -6.725047 9.418979 -0.984070 +v -6.858561 9.322436 -0.975397 +v -7.255682 9.258713 -0.958595 +v -7.267346 9.229938 -0.754402 +v -7.353399 9.213202 -0.756218 +v -7.244332 8.721568 -0.846787 +v -7.227530 8.824084 -1.064345 +v -7.613669 8.792569 -1.068179 +v -7.656551 9.088012 -1.146608 +v -7.902184 9.119670 -1.123861 +v -7.706452 9.232306 -0.947764 +v -8.011127 9.129695 -1.040889 +v -8.011755 9.190997 -0.843967 +v -5.016000 7.943977 -0.117054 +v -5.241756 7.976788 -0.120869 +v -5.016000 8.100374 0.381608 +v -5.241756 8.124455 0.365776 +v -5.016000 8.383518 0.684271 +v -5.241756 8.409492 0.661970 +v -5.016001 8.818721 0.749269 +v -5.241756 8.818321 0.722177 +v -4.906000 8.065040 -0.156215 +v -4.906000 8.188643 0.271229 +v -4.906000 8.470452 0.531707 +v -4.906000 8.880107 0.590127 +v -4.906000 9.226704 0.458523 +v -5.016000 9.252052 0.591797 +v -4.906000 9.477948 0.132612 +v -5.016000 9.569269 0.208490 +v -4.906000 9.526071 -0.283359 +v -5.016000 9.633473 -0.282759 +v -5.349171 8.817339 0.597260 +v -5.241756 9.248844 0.571962 +v -5.241756 9.551197 0.197599 +v -5.241756 9.603356 -0.281225 +v -5.342718 9.120031 0.464921 +v -5.341683 9.395922 0.204245 +v -5.340926 9.477347 -0.287148 +v -7.839791 8.815664 -1.048266 +v -8.036589 8.968635 -0.913329 +v -7.863250 8.757035 -0.863347 +v -7.855858 8.867503 -0.716371 +v -7.632369 8.860678 -0.693226 +v -7.681002 9.213459 -0.731723 +v -5.760902 9.531161 0.282299 +v -5.762764 9.626752 -0.289384 +v -7.642303 8.711930 -0.845260 +v -7.263626 8.893267 -0.705037 +v -7.229478 9.084154 -1.142675 +v -7.344015 9.241508 -0.955794 +v -6.410755 9.632900 0.345232 +v -6.431504 9.721017 -0.101324 +v -7.315837 9.081507 -1.134364 +v -6.168511 9.697254 0.195809 +v -5.241756 8.790450 -0.218442 +v -6.180233 9.746678 -0.315037 +v -6.166735 9.597584 -0.811177 +v -7.932877 9.221364 -0.741215 +v 4.906000 9.526071 -0.283360 +v 4.906000 9.385558 -0.729063 +v 5.016000 9.633474 -0.282761 +v 5.016000 9.461336 -0.797987 +v 5.241756 9.603357 -0.281227 +v 5.241756 9.447243 -0.777777 +v 5.340926 9.477347 -0.287148 +v 5.332999 9.362614 -0.732852 +v 5.758732 9.415091 -0.906100 +v 5.346495 9.027624 -0.901556 +v 5.755214 9.048763 -1.120826 +v 5.346349 8.631769 -0.952314 +v 5.751696 8.602972 -1.059812 +v 5.346607 8.374742 -0.787549 +v 5.745581 8.288541 -0.819154 +v 5.347149 8.216182 -0.537451 +v 5.745901 8.139385 -0.416817 +v 5.347767 8.129204 -0.101954 +v 4.906000 8.880109 0.590125 +v 4.906000 9.226703 0.458522 +v 5.016000 8.818721 0.749268 +v 5.016000 9.252053 0.591796 +v 5.241756 8.818321 0.722176 +v 5.241756 9.248846 0.571961 +v 5.349170 8.817338 0.597260 +v 5.342718 9.120031 0.464921 +v 5.759155 9.243464 0.593572 +v 5.760902 9.531161 0.282299 +v 4.906000 9.477948 0.132611 +v 5.016000 9.569270 0.208488 +v 5.241756 9.551199 0.197598 +v 5.341683 9.395922 0.204245 +v 5.762764 9.626752 -0.289384 +v 8.044008 8.991931 -0.348751 +v 8.216845 9.123877 -0.503843 +v 8.033489 8.875972 -0.463722 +v 8.038750 8.946250 -0.636592 +v 7.773302 8.823855 -0.451986 +v 7.748329 8.907350 -0.659377 +v 7.342511 8.829979 -0.445761 +v 7.340392 8.917072 -0.643712 +v 6.780320 8.858656 -0.657140 +v 4.906000 8.188643 0.271227 +v 4.906000 8.470453 0.531706 +v 5.016000 8.100374 0.381607 +v 5.016000 8.383519 0.684270 +v 5.241756 8.124456 0.365775 +v 5.241756 8.409492 0.661969 +v 5.348429 8.228843 0.268001 +v 5.348994 8.399103 0.523214 +v 4.906000 8.668272 -1.001495 +v 4.906000 8.320722 -0.862618 +v 5.016000 8.616241 -1.110398 +v 5.016000 8.206285 -0.945126 +v 5.241756 8.622485 -1.076170 +v 5.241756 8.237028 -0.920329 +v 4.906000 8.098462 -0.577438 +v 5.016000 7.989540 -0.609758 +v 5.241756 8.021846 -0.596907 +v 4.906000 8.065041 -0.156217 +v 5.016000 7.943978 -0.117056 +v 5.241756 7.976789 -0.120870 +v 4.906000 9.072752 -0.976057 +v 5.016000 9.071982 -1.083924 +v 5.241756 9.075203 -1.051955 +v 8.112273 9.380780 -0.336060 +v 7.810650 9.382998 -0.292275 +v 7.756835 8.964725 -0.304100 +v 7.458974 9.358718 -0.305856 +v 7.347110 8.975099 -0.307279 +v 7.372396 9.372733 -0.307057 +v 6.840041 9.503676 -0.319305 +v 6.817776 8.754169 -0.430132 +v 6.766116 9.361799 -0.750883 +v 7.343761 9.277564 -0.723250 +v 7.447306 9.267234 -0.718223 +v 7.798518 9.278988 -0.757804 +v 7.841775 9.416004 -0.538718 +v 7.474545 9.421887 -0.538703 +v 7.382454 9.426131 -0.541293 +v 6.962314 9.485082 -0.546023 +v 6.816284 9.603394 -0.545407 +v 5.880557 8.025978 0.563838 +v 6.028211 8.074326 0.276071 +v 6.160312 8.300775 -0.008148 +v 8.179666 9.314499 -0.639024 +v 8.179555 9.360184 -0.430255 +v 5.241756 8.790450 -0.218444 +v 8.087163 9.293324 -0.735648 +v 6.855141 8.935000 -0.267220 +v 5.749849 8.193149 0.823555 +v 5.509262 8.688492 0.739440 +v 5.756501 8.879025 0.785506 +v 5.708315 8.528291 0.916221 +v 6.571239 8.845071 0.660922 +v 6.840092 8.707955 0.674622 +v 6.308940 8.942181 0.839121 +v 6.722010 8.769037 1.029889 +v 6.203051 8.859719 1.028546 +v 6.723957 8.527247 1.155483 +v 6.160355 8.527845 1.153063 +v 6.717686 8.240335 1.072672 +v 6.177991 8.197435 1.075377 +v 6.248789 8.041136 0.823664 +v 7.474892 8.520160 1.096026 +v 7.472132 8.504060 0.856924 +v 7.362447 8.255562 1.011993 +v 7.342677 8.258614 0.740245 +v 7.132931 8.212914 1.013866 +v 7.130949 8.210622 0.686298 +v 6.840899 8.249853 0.705505 +v 6.350201 8.109765 0.578347 +v 7.323745 8.464379 0.611797 +v 7.335336 8.689918 0.695687 +v 7.354871 8.763054 0.977158 +v 7.124813 8.717812 0.644927 +v 7.102796 8.785804 0.970555 +v 6.775223 8.944337 0.629420 +v 6.774453 9.332330 0.618401 +v 6.398506 9.245222 0.716288 +v 6.398215 9.449624 0.554758 +v 7.119768 8.464378 0.559010 +v 6.811357 8.471261 0.587308 +v 7.158222 8.525597 1.096398 +v 6.437701 8.458210 0.358747 +v 6.801850 8.768547 0.384918 +v 6.176432 9.597869 0.277498 +v 6.166216 9.661924 0.247118 +v 6.321032 9.627039 0.264155 +v 6.261107 9.680712 0.240395 +v 6.384912 9.649674 0.202779 +v 6.302738 9.694655 0.204997 +v 6.330651 9.652513 0.129326 +v 6.266725 9.695588 0.161660 +v 6.190035 9.633893 0.086821 +v 6.174158 9.682962 0.135771 +v 6.045433 9.604719 0.100165 +v 6.079271 9.664174 0.142495 +v 5.981553 9.582085 0.161539 +v 6.037639 9.650230 0.177893 +v 6.035814 9.579247 0.234993 +v 6.073654 9.649300 0.221229 +v 6.186670 9.560635 -0.690630 +v 6.172019 9.597438 -0.749478 +v 6.327709 9.565610 -0.735444 +v 6.264869 9.601554 -0.777028 +v 6.381895 9.544566 -0.805987 +v 6.300855 9.589767 -0.818793 +v 6.317491 9.509827 -0.860935 +v 6.258902 9.568978 -0.850310 +v 6.172222 9.481747 -0.868101 +v 6.163583 9.551371 -0.853115 +v 6.031186 9.476772 -0.823287 +v 6.070733 9.547254 -0.825566 +v 5.976995 9.497818 -0.752745 +v 6.034743 9.559041 -0.783800 +v 6.041401 9.532553 -0.697795 +v 6.076698 9.579830 -0.752284 +v 6.191704 9.674240 -0.210002 +v 6.181599 9.727705 -0.255999 +v 6.335401 9.686331 -0.243604 +v 6.276094 9.735878 -0.276009 +v 6.393492 9.685179 -0.314114 +v 6.314402 9.735666 -0.317346 +v 6.331944 9.671457 -0.380228 +v 6.274076 9.727192 -0.355793 +v 6.186815 9.653202 -0.403218 +v 6.178744 9.715420 -0.368828 +v 6.043116 9.641110 -0.369615 +v 6.084248 9.707247 -0.348818 +v 5.985028 9.642263 -0.299106 +v 6.045944 9.707458 -0.307482 +v 6.046573 9.655986 -0.232992 +v 6.086267 9.715933 -0.269035 +v 6.369055 8.300657 -0.431480 +v 6.369000 8.420352 -0.887948 +v 6.368480 8.653156 -1.115954 +v 6.379901 9.087399 -1.202902 +v 6.661691 9.117439 -1.179774 +v 6.391321 9.336958 -1.132231 +v 6.406479 9.481428 -0.959757 +v 6.430676 9.669760 -0.555716 +v 6.431504 9.721017 -0.101324 +v 6.410755 9.632900 0.345232 +v 8.282977 9.122375 0.387234 +v 8.122756 8.910866 0.363286 +v 8.114070 8.997998 0.579771 +v 7.886303 8.941163 0.599779 +v 7.919818 9.295051 0.642630 +v 7.471507 9.285270 0.619852 +v 7.485582 9.400188 0.386793 +v 7.393487 9.399495 0.386851 +v 7.382149 9.374518 0.187496 +v 6.813945 9.462175 0.165748 +v 6.813742 9.567743 0.374198 +v 6.961170 9.461555 0.388416 +v 6.840199 9.653583 -0.094610 +v 7.002219 9.536085 -0.089993 +v 7.426173 9.490965 -0.092085 +v 7.414295 9.362523 0.154873 +v 7.905248 8.834842 0.367205 +v 7.361333 8.928007 0.577167 +v 7.370884 9.285695 0.619366 +v 6.725046 9.418979 -0.984071 +v 7.477827 9.373614 0.192253 +v 7.946066 9.435209 0.387191 +v 8.150703 9.316319 0.612214 +v 6.686448 8.797213 -1.063444 +v 6.733444 8.646388 -0.818458 +v 7.370905 8.965878 0.190423 +v 7.901571 9.392712 0.149599 +v 7.875789 8.969199 0.166442 +v 8.140301 9.382042 0.155003 +v 8.101300 9.034930 0.185360 +v 6.828564 8.948880 0.168618 +v 7.398368 8.963255 0.130057 +v 6.841867 8.797432 -0.034165 +v 7.396554 8.865445 -0.049804 +v 7.396999 8.974939 -0.251266 +v 7.364923 8.842179 0.362676 +v 6.168511 9.697255 0.195809 +v 8.265511 9.367288 0.283105 +v 8.266574 9.339490 0.497188 +v 6.180234 9.746678 -0.315037 +v 6.166735 9.597584 -0.811178 +v 7.404204 9.377501 -0.312260 +v -8.265511 9.367287 0.283105 +v -8.266574 9.339488 0.497188 +v -8.282977 9.122375 0.387234 +v -8.114071 8.997996 0.579772 +v -8.122756 8.910864 0.363287 +v -7.886303 8.941161 0.599780 +v -7.905248 8.834840 0.367205 +v 7.507607 9.353236 0.152010 +v 7.836949 8.986317 0.153543 +v 7.852835 8.884461 -0.046135 +v 8.134693 8.946482 -0.046380 +v 8.118917 9.013198 -0.240438 +v 8.314709 9.178496 -0.061270 +v 8.309418 9.408785 -0.194007 +v 7.518939 9.493416 -0.092176 +v 7.888583 9.394939 0.179237 +v 7.925028 9.486908 -0.088352 +v 8.203904 9.418515 0.155647 +v 8.312749 9.417868 0.035639 +v -7.477827 9.373614 0.192253 +v -7.901570 9.392711 0.149600 +v -7.875789 8.969197 0.166442 +v -8.140301 9.382040 0.155004 +v -8.101299 9.034928 0.185360 +v -8.150702 9.316319 0.612214 +v -7.946065 9.435208 0.387192 +v -7.919817 9.295051 0.642631 +v -7.485582 9.400188 0.386793 +v -7.471507 9.285270 0.619852 +v 8.121567 9.030011 0.135721 +v 7.830240 8.979107 -0.266181 +v 7.887812 9.395960 -0.336688 +v 7.511127 9.376824 -0.311996 +v 8.212494 9.414018 -0.310115 +v 7.244332 8.721568 -0.846788 +v 7.227530 8.824084 -1.064345 +v 7.229478 9.084154 -1.142676 +v 7.315837 9.081506 -1.134364 +v 7.344015 9.241508 -0.955794 +v 7.706452 9.232306 -0.947764 +v 7.681003 9.213459 -0.731723 +v 7.932877 9.221363 -0.741215 +v 7.855859 8.867503 -0.716371 +v 7.632369 8.860678 -0.693227 +v 7.353399 9.213202 -0.756218 +v 7.263627 8.893267 -0.705038 +v 7.267347 9.229937 -0.754403 +v 7.902186 9.119669 -1.123861 +v 7.839791 8.815664 -1.048266 +v 8.011128 9.129695 -1.040890 +v 8.036589 8.968635 -0.913330 +v 8.011756 9.190997 -0.843967 +v 7.656552 9.088011 -1.146608 +v 7.613670 8.792569 -1.068180 +v 7.255682 9.258713 -0.958595 +v 6.858561 9.322436 -0.975397 +v 7.642305 8.711930 -0.845261 +v 7.863251 8.757035 -0.863347 +v 0.408221 0.194972 -0.112917 +v 0.268156 0.172328 0.690018 +v 0.248934 -0.058214 0.678919 +v 0.125968 0.159554 1.373911 +v 0.123156 -0.070000 1.374829 +v 0.239447 0.175510 1.939033 +v 0.245893 -0.069999 1.928565 +v 0.537359 0.183830 2.309637 +v 0.551283 -0.048421 2.292526 +v 0.897746 0.205042 2.503279 +v 0.902119 -0.021418 2.479529 +v 1.242879 0.203594 2.540499 +v 1.242878 -0.021418 2.514676 +v 1.683657 0.199770 2.457462 +v 1.687587 -0.021418 2.428272 +v 2.019134 0.174826 2.177141 +v 2.030269 -0.048421 2.149549 +v 2.282666 0.165795 1.774598 +v 2.281803 -0.069999 1.765275 +v 2.359935 0.147109 1.239357 +v 2.348065 -0.070000 1.252153 +v 2.292352 0.164063 0.570714 +v 2.287176 -0.058214 0.563024 +v 2.065928 0.194030 -0.107174 +v 0.810528 1.793944 0.958012 +v 0.560311 1.742497 -0.079454 +v 0.785508 1.801146 0.447738 +v 1.242853 1.637601 -0.574302 +v 1.242845 1.839348 0.506744 +v 1.480668 1.807682 0.453065 +v 1.242862 1.840948 1.009353 +v 1.605209 1.801327 0.965935 +v 1.242868 1.808867 1.605485 +v 1.674563 1.762520 1.528331 +v 1.621152 1.569483 2.190415 +v 1.968144 1.555936 1.991277 +v 2.099053 1.066873 2.352208 +v 2.355761 1.374025 1.303907 +v 2.552756 0.959976 1.394507 +v 2.350543 1.274594 0.671092 +v 2.490862 0.871833 0.674804 +v 2.008432 1.025325 -0.836651 +v 2.116729 0.685382 -0.884356 +v 1.622363 0.996026 -1.372792 +v 1.614471 0.685149 -1.438537 +v 1.242852 0.989570 -1.482055 +v 1.242851 0.683829 -1.533184 +v 0.765974 0.986880 -1.376550 +v 1.242882 0.531507 2.749427 +v 0.831456 0.532223 2.711568 +v 1.242864 1.128435 2.686484 +v 0.754842 1.117297 2.611827 +v 0.820808 1.561739 2.179241 +v 0.441337 1.539368 1.938851 +v 0.777863 1.753833 1.518724 +v 0.443679 1.625729 1.478298 +v 0.419243 1.561091 0.747960 +v 0.422882 1.196497 -0.121814 +v 0.560501 1.446021 -0.658926 +v 0.405627 1.006610 -0.843620 +v 0.733680 0.676787 -1.442826 +v 1.242852 0.409261 -1.497866 +v 1.565368 0.407359 -1.418128 +v 1.502278 0.181566 -1.286971 +v 1.783165 0.171501 -1.082777 +v 0.426655 0.468378 2.475025 +v 0.318280 1.052104 2.345769 +v 0.096845 0.458845 2.061903 +v -0.073522 0.934139 1.399780 +v -0.062717 0.436554 1.436121 +v 0.021951 0.457269 0.714812 +v 2.507276 0.464805 0.562084 +v 2.565553 0.439997 1.268228 +v 2.428239 0.462676 1.881716 +v 2.116783 0.470515 2.339771 +v 1.753369 0.533044 2.663719 +v 1.242852 0.200497 -1.360419 +v 0.755689 0.401610 -1.422280 +v 0.832580 0.179895 -1.290324 +v 0.444416 0.368910 -1.174170 +v 0.564723 0.177220 -1.066914 +v 0.321548 0.360574 -0.844802 +v 0.452424 0.170486 -0.770327 +v 1.902974 0.379907 -1.190680 +v 2.134184 0.374731 -0.836752 +v 1.967425 -0.069999 -0.770507 +v 1.776986 -0.069999 -1.089848 +v 1.497289 -0.070000 -1.292291 +v 1.242851 -0.053358 -1.367393 +v 0.834361 -0.070000 -1.295780 +v 1.480693 1.452423 -1.173853 +v 1.819023 1.454595 -0.653658 +v 1.791329 1.744484 -0.077548 +v 0.313948 0.665296 -0.892556 +v 0.310093 0.807592 -0.106755 +v 0.160444 1.244790 0.671666 +v 0.056194 0.842336 0.674332 +v 0.119212 1.346943 1.310921 +v 1.675249 1.123937 2.598735 +v 1.242866 1.598523 2.247332 +v 0.293591 0.472306 -0.122851 +v 0.428774 -0.049198 -0.130465 +v 2.013820 -0.049198 -0.126571 +v 0.433365 -0.070000 -0.779311 +v 0.557591 -0.070000 -1.073903 +v 0.915244 1.443055 -1.176252 +v 1.974932 0.171365 -0.762916 +v 2.078876 1.577329 0.750381 +v 2.037605 1.641777 1.486725 +v 0.000000 11.050320 2.348916 +v 0.544102 10.979750 2.492094 +v 0.000000 10.720880 2.764549 +v 0.339555 10.648720 2.775601 +v 0.000000 10.426170 2.789184 +v 0.382455 10.457690 2.762593 +v 0.408211 10.307930 2.710463 +v 0.176652 10.195230 2.617792 +v 0.000000 10.276280 2.678418 +v -0.176652 10.195230 2.617792 +v -0.144427 10.162700 2.492784 +v -0.408211 10.307930 2.710463 +v -0.382455 10.457690 2.762593 +v -0.339555 10.648720 2.775601 +v -0.546731 10.979750 2.492094 +v 0.000000 10.227460 2.539783 +v 0.144427 10.162700 2.492784 +v -0.621212 10.749790 2.592853 +v -0.664241 10.569360 2.650137 +v -0.600317 10.266620 2.472846 +v -0.417932 10.187860 2.547551 +v -0.389601 10.147280 2.391039 +v 0.389601 10.147280 2.391039 +v 0.593558 10.238680 2.307821 +v 0.691224 10.393190 2.289150 +v 0.500967 11.076550 2.294785 +v 0.696147 10.443340 2.420891 +v 0.597688 10.266620 2.472846 +v 0.661613 10.569360 2.650137 +v 0.417932 10.187860 2.547551 +v -0.698776 10.443340 2.420891 +v -0.596187 10.238680 2.307821 +v -0.693852 10.393190 2.289150 +v -0.495321 11.076550 2.294786 +v 0.618583 10.749790 2.592853 +v -0.769303 11.106310 2.207106 +v -0.829810 11.017940 2.407622 +v -1.011266 11.165850 2.126488 +v -1.075204 11.093900 2.316191 +v -1.245132 11.252260 2.039242 +v -1.313760 11.238780 2.130111 +v -1.372299 11.335280 1.961746 +v -1.424142 11.331880 2.023068 +v -1.536293 11.492590 1.840454 +v -1.494540 11.271270 2.071892 +v -1.560785 11.210210 2.038554 +v -1.480495 11.048370 2.166071 +v -1.544301 10.953370 2.104611 +v -1.225187 10.838340 2.366741 +v -1.436116 10.751180 2.108263 +v -1.275345 10.733040 2.246593 +v -1.281997 10.708160 2.100011 +v -1.273741 10.529800 2.093641 +v 0.769304 11.106310 2.207106 +v 0.829811 11.017940 2.407622 +v 0.904662 10.868530 2.505980 +v 0.986903 10.694430 2.524841 +v 1.039586 10.542000 2.486864 +v 1.225188 10.838340 2.366741 +v 1.254653 10.563160 2.218377 +v 1.275346 10.733040 2.246593 +v 1.273741 10.529800 2.093641 +v 1.281998 10.708160 2.100011 +v 1.011267 11.165850 2.126488 +v 1.245133 11.252270 2.039242 +v 1.075205 11.093900 2.316191 +v 1.313761 11.238780 2.130110 +v 1.153966 10.971760 2.376338 +v 1.396860 11.146980 2.191891 +v 1.480496 11.048370 2.166071 +v 1.544302 10.953370 2.104611 +v 1.560786 11.210210 2.038553 +v 1.661124 11.070780 1.884776 +v 1.617179 11.327330 1.825433 +v 1.638892 11.052640 1.746502 +v 1.604018 11.334030 1.748725 +v -1.405134 10.724750 1.978245 +v -1.562298 10.842800 1.988108 +v -1.661124 11.070780 1.884776 +v -1.617178 11.327330 1.825433 +v -1.604017 11.334030 1.748725 +v -0.904661 10.868530 2.505980 +v -1.153965 10.971760 2.376338 +v -1.396859 11.146980 2.191891 +v -0.986902 10.694430 2.524841 +v -1.039586 10.542000 2.486864 +v -0.874869 10.354630 2.351061 +v -0.844879 10.317190 2.215156 +v -1.103208 10.377010 2.276289 +v -1.254653 10.563160 2.218377 +v 1.540569 10.812400 1.852505 +v 1.562299 10.842800 1.988108 +v 1.436116 10.751180 2.108263 +v 1.098488 10.338330 2.136102 +v 1.103208 10.377010 2.276289 +v 0.885849 10.354630 2.351061 +v -1.098488 10.338330 2.136102 +v -1.540568 10.812400 1.852505 +v 1.405135 10.724750 1.978245 +v -1.638892 11.052640 1.746503 +v 1.536294 11.492590 1.840454 +v 1.494540 11.271270 2.071892 +v 1.372300 11.335280 1.961746 +v 1.424143 11.331880 2.023068 +v 0.855438 10.317190 2.215154 +v -0.384205 0.188538 -0.118628 +v -0.273185 0.164385 0.684249 +v -0.025135 0.448521 0.708174 +v -0.141680 0.149690 1.364562 +v 0.048857 0.426134 1.426145 +v -0.253290 0.165856 1.930188 +v -0.108665 0.448832 2.052636 +v -0.550322 0.175416 2.302079 +v -0.437489 0.459736 2.467184 +v -0.910473 0.198315 2.497293 +v -0.841764 0.525524 2.705519 +v -1.244933 0.197065 2.536049 +v -1.244942 0.525231 2.745237 +v -1.697797 0.196939 2.454871 +v -1.765270 0.530927 2.661658 +v -2.034920 0.173790 2.175986 +v -2.130708 0.470301 2.339241 +v -2.300339 0.155619 1.774580 +v -2.444306 0.453598 1.882533 +v -2.379669 0.137643 1.239657 +v -2.584065 0.431972 1.269625 +v -2.301019 0.155473 0.573687 +v -2.514824 0.457741 0.566201 +v -2.044480 0.195765 -0.105718 +v -2.114484 0.377565 -0.834857 +v -1.955690 0.173065 -0.761850 +v -1.764733 0.172471 -1.082532 +v -0.255114 -0.058214 0.672903 +v -0.139924 -0.070000 1.365315 +v -0.260848 -0.070000 1.919594 +v -0.565452 -0.048422 2.284868 +v -0.916181 -0.021419 2.473385 +v -1.244930 -0.021419 2.510034 +v -1.703044 -0.021419 2.425525 +v -2.047293 -0.048422 2.148280 +v -2.300572 -0.070000 1.765100 +v -2.368803 -0.070000 1.252249 +v -2.297002 -0.058214 0.565812 +v -1.985365 1.028520 -0.834846 +v -1.456277 1.453824 -1.173989 +v -1.793166 1.457289 -0.652249 +v -1.244788 1.640026 -0.575198 +v -1.761927 1.747147 -0.076049 +v -1.448530 1.808665 0.453178 +v -1.567596 1.802622 0.966566 +v -1.244747 1.842314 0.505993 +v -1.244816 1.842549 1.008669 +v -0.752331 1.798861 0.444665 +v -0.771741 1.791502 0.954999 +v -0.529035 1.739373 -0.083597 +v -0.381745 1.556578 0.742974 +v -0.394026 1.191658 -0.126758 +v -0.124426 1.238228 0.665557 +v -0.021977 0.834647 0.667489 +v 0.097694 0.924722 1.389486 +v -0.268083 0.465733 -0.128863 +v -0.282916 0.801596 -0.112461 +v -0.290195 0.659628 -0.898328 +v -0.380176 1.001880 -0.848756 +v -0.743005 0.984261 -1.380128 +v -0.889985 1.441795 -1.178981 +v -1.244790 0.991394 -1.483529 +v -1.600668 0.997641 -1.372659 +v -1.594511 0.686297 -1.438655 +v -2.095650 0.688631 -0.882318 +v -1.884129 0.371156 -1.189775 +v -1.484004 0.181321 -1.287920 +v -1.546621 0.407830 -1.418652 +v -1.244790 0.410153 -1.499769 +v -1.244787 0.685239 -1.534890 +v -0.735723 0.398084 -1.426310 +v -0.712406 0.673583 -1.446758 +v -0.423283 0.363628 -1.179578 +v -0.299130 0.354450 -0.850756 +v -0.412954 -0.070000 -0.785077 +v -0.544335 0.172171 -1.071936 +v -0.538396 -0.070000 -1.079126 +v -0.813272 0.176351 -1.294167 +v -0.816372 -0.070000 -1.299802 +v -1.244792 0.200930 -1.362472 +v -1.244790 -0.053358 -1.369649 +v -1.480298 -0.070000 -1.293445 +v -1.759749 -0.070000 -1.089799 +v -1.949380 -0.070000 -0.769643 +v -2.043875 1.580629 0.753006 +v -2.012880 1.643992 1.486225 +v -1.648522 1.763197 1.526267 +v -1.942042 1.557140 1.990234 +v -1.593722 1.568873 2.187880 +v -1.648660 1.122648 2.596113 +v -1.244833 1.126355 2.682152 +v -0.430832 0.164686 -0.775842 +v -0.726811 1.111449 2.605221 +v -0.290839 1.044174 2.337231 +v -0.792206 1.557179 2.173241 +v -0.413110 1.533055 1.931198 +v -0.750508 1.750292 1.512547 +v -0.416576 1.620445 1.470488 +v -1.993612 -0.049198 -0.125521 +v -0.406106 -0.049198 -0.136267 +v -2.317814 1.268187 0.674470 +v -2.333562 1.366631 1.304423 +v -2.460296 0.865508 0.678508 +v -2.532560 0.952870 1.395585 +v -2.074283 1.067744 2.351380 +v -0.532773 1.442790 -0.663289 +v -0.093621 1.339163 1.301751 +v -1.244847 1.808661 1.601721 +v -1.244841 1.597321 2.243361 +v 2.002699 12.741300 1.183479 +v 2.081975 12.830400 1.185901 +v 2.241549 12.437940 0.263324 +v 2.574750 12.732140 0.199441 +v 2.525460 12.459320 -0.591549 +v 2.625496 12.767480 -0.669439 +v 2.284350 12.512920 -1.303541 +v 2.252996 12.738190 -1.398792 +v 1.845202 12.333980 -1.818925 +v 1.863100 12.563120 -1.931464 +v 1.191273 12.398700 -2.424957 +v 1.136227 12.641600 -2.525019 +v 0.405515 12.563890 -2.720665 +v 0.374752 12.834760 -2.772994 +v 0.000000 12.563890 -2.720665 +v 0.000000 12.834760 -2.772994 +v -0.374752 12.834760 -2.772994 +v -0.325198 13.114470 -2.735470 +v -1.050031 12.896140 -2.571662 +v -0.911183 13.159560 -2.551772 +v -1.640184 13.025900 -2.088034 +v -1.425575 13.219970 -2.133576 +v -1.721155 13.246760 -1.636075 +v -1.372576 13.417940 -1.715922 +v -1.964067 13.597680 -1.197071 +v -1.566292 13.714970 -1.373892 +v -2.012233 14.055640 -0.625738 +v -1.631092 14.103430 -0.929106 +v -1.878852 14.514810 -0.023966 +v -1.531352 14.495400 -0.461242 +v -1.583821 14.927110 0.478831 +v -1.301303 14.856450 -0.028883 +v -1.124246 15.303040 0.920658 +v -0.941244 15.144630 0.313585 +v -0.517933 15.530920 1.221739 +v -0.439053 15.341900 0.543669 +v 0.000000 15.600990 1.315438 +v 0.000000 15.393710 0.594125 +v 0.439053 15.341900 0.543669 +v 0.311037 14.889210 -0.283179 +v 0.941244 15.144630 0.313585 +v 0.887483 14.587220 -0.620468 +v 1.301303 14.856450 -0.028883 +v 1.531352 14.495400 -0.461242 +v 1.583821 14.927110 0.478832 +v 1.878852 14.514810 -0.023966 +v 1.768582 14.831510 0.903964 +v 2.142248 14.401390 0.349884 +v 1.885487 14.616600 1.292858 +v 2.325337 14.163730 0.647522 +v 1.980834 14.237060 1.547309 +v 2.421426 13.822920 0.869771 +v 1.999153 13.777990 1.720503 +v 2.461212 13.440400 0.993218 +v 1.932320 13.319120 1.696842 +v 2.399050 13.040250 0.997210 +v 1.866518 13.106050 1.582219 +v 2.678446 13.093480 0.165107 +v 2.570970 13.030940 -0.764524 +v 2.146247 12.951260 -1.498227 +v 1.774825 12.803730 -2.017893 +v 1.050032 12.896140 -2.571662 +v 0.325198 13.114470 -2.735471 +v 0.000000 13.114470 -2.735471 +v -0.259336 13.385340 -2.584223 +v -0.726644 13.411210 -2.449860 +v -1.099776 13.413290 -2.135526 +v -0.955170 13.549890 -1.777467 +v -1.151196 14.031740 -1.232262 +v 2.182940 12.175290 -0.552939 +v 2.162947 12.254090 -1.185487 +v 1.672860 11.912580 -1.495767 +v 1.786519 12.085010 -1.710327 +v 1.142628 11.956390 -2.094085 +v 1.200460 12.163690 -2.282629 +v 0.421247 12.089830 -2.472340 +v 0.425685 12.311140 -2.612902 +v 0.000000 12.089830 -2.472340 +v 0.000000 12.311140 -2.612902 +v -0.425685 12.311140 -2.612902 +v -0.405515 12.563890 -2.720665 +v -1.191273 12.398700 -2.424957 +v -1.136227 12.641590 -2.525018 +v -1.863101 12.563120 -1.931464 +v -1.774825 12.803730 -2.017893 +v -2.146247 12.951260 -1.498227 +v -1.983430 13.102030 -1.568564 +v -2.449152 13.271210 -0.895905 +v -2.263358 13.442610 -1.032875 +v -2.498589 13.717200 -0.125136 +v -2.306859 13.918010 -0.350063 +v 2.622325 13.401000 0.066817 +v 2.449152 13.271220 -0.895905 +v 1.983430 13.102030 -1.568565 +v 1.640184 13.025900 -2.088034 +v 0.911183 13.159560 -2.551772 +v 0.259336 13.385340 -2.584223 +v 0.000000 13.385340 -2.584223 +v -0.180471 13.562560 -2.377628 +v -0.505669 13.552440 -2.278130 +v 2.498590 13.717200 -0.125136 +v 2.263358 13.442610 -1.032875 +v 1.721155 13.246760 -1.636075 +v 1.425575 13.219970 -2.133576 +v 0.726644 13.411210 -2.449860 +v 0.180471 13.562560 -2.377628 +v 0.000000 13.562560 -2.377628 +v -0.092557 13.620600 -2.171581 +v -0.259336 13.616490 -2.121057 +v -0.489867 13.635100 -1.817200 +v 0.000000 13.663990 -1.830672 +v 0.510618 11.732850 -2.072831 +v 0.407584 11.893960 -2.284010 +v 0.000000 11.732850 -2.072831 +v 0.000000 11.893960 -2.284010 +v -0.407584 11.893960 -2.284010 +v -0.421247 12.089830 -2.472340 +v -1.142628 11.956390 -2.094086 +v -1.200460 12.163690 -2.282630 +v -1.786519 12.085010 -1.710327 +v -1.845202 12.333980 -1.818925 +v -2.284350 12.512920 -1.303541 +v -2.252997 12.738190 -1.398792 +v -2.625496 12.767480 -0.669439 +v -2.570970 13.030940 -0.764524 +v -2.678446 13.093480 0.165107 +v -2.622325 13.401000 0.066817 +v -2.002699 12.741300 1.183480 +v -2.241549 12.437940 0.263324 +v -2.081975 12.830400 1.185901 +v -2.574750 12.732140 0.199441 +v -2.399050 13.040250 0.997210 +v -2.461212 13.440400 0.993218 +v -2.421426 13.822920 0.869771 +v -2.325337 14.163730 0.647522 +v -2.142248 14.401390 0.349884 +v 2.306859 13.918010 -0.350063 +v 1.964067 13.597680 -1.197071 +v 1.372576 13.417940 -1.715922 +v 1.099776 13.413290 -2.135526 +v 0.505669 13.552440 -2.278130 +v 0.092557 13.620600 -2.171581 +v 2.012233 14.055640 -0.625738 +v 1.631092 14.103440 -0.929106 +v 1.566292 13.714970 -1.373892 +v 1.151196 14.031740 -1.232262 +v 0.955170 13.549890 -1.777467 +v 0.489867 13.635100 -1.817200 +v 0.259336 13.616490 -2.121057 +v -0.510618 11.732850 -2.072831 +v -1.672860 11.912580 -1.495767 +v -2.162947 12.254090 -1.185487 +v -2.525460 12.459320 -0.591549 +v 0.000000 13.340580 3.795632 +v 0.000000 13.222090 3.758816 +v -0.902178 13.291760 3.636122 +v -0.871650 13.177960 3.603193 +v -1.611580 13.095140 3.192088 +v -1.551306 12.992560 3.170801 +v -2.038270 12.867910 2.460660 +v -1.962781 12.775320 2.452682 +v -2.147727 12.782450 1.642909 +v -2.068450 12.693350 1.640489 +v -1.759604 12.854740 1.492988 +v -1.310936 13.022090 1.931028 +v -0.623117 13.127620 2.157331 +v 0.000000 13.154620 2.215231 +v 0.871650 13.177960 3.603193 +v -0.680708 15.234070 2.258126 +v 0.000000 15.302660 2.360739 +v -0.876438 14.798320 2.421022 +v 0.000000 14.857940 2.584260 +v 0.000000 14.223620 2.622637 +v 0.876438 14.798320 2.421022 +v 0.934663 14.175710 2.458472 +v 1.469759 14.556380 2.079924 +v 1.513355 13.992920 2.153754 +v 0.000000 14.889210 -0.283179 +v -0.311037 14.889210 -0.283179 +v -0.158168 14.337930 -1.058438 +v -0.463402 14.174070 -1.227232 +v -0.590401 13.884260 -1.538700 +v -0.903541 13.738190 2.360177 +v -1.471347 13.464000 2.060425 +v -0.934663 14.175710 2.458472 +v -1.513355 13.992920 2.153755 +v -1.469759 14.556380 2.079924 +v -1.980834 14.237050 1.547309 +v -1.885487 14.616600 1.292858 +v -1.372759 14.956800 1.814548 +v -1.273091 15.225890 1.425198 +v -0.605150 15.486370 1.837900 +v 0.000000 15.547620 1.929651 +v 0.605150 15.486370 1.837900 +v 0.517933 15.530920 1.221740 +v 1.124246 15.303040 0.920658 +v 1.611580 13.095140 3.192088 +v 1.471347 13.464000 2.060425 +v 0.902178 13.291760 3.636122 +v 0.903541 13.738190 2.360177 +v 0.000000 13.803200 2.523331 +v -1.866519 13.106050 1.582219 +v -1.932321 13.319120 1.696842 +v -1.999153 13.777990 1.720503 +v 0.680708 15.234070 2.258126 +v 1.372759 14.956800 1.814548 +v 1.273091 15.225890 1.425198 +v 0.000000 13.620600 -2.171581 +v -0.887483 14.587220 -0.620468 +v 0.590401 13.884260 -1.538700 +v 0.463402 14.174070 -1.227232 +v 0.158168 14.337930 -1.058438 +v 0.000000 14.337930 -1.058438 +v 0.000000 13.698120 -0.167046 +v 0.000000 13.500030 1.623332 +v 1.759604 12.854740 1.492988 +v 1.310937 13.022090 1.931028 +v -2.182940 12.175290 -0.552939 +v -1.768582 14.831510 0.903964 +v 2.147727 12.782450 1.642909 +v 2.038270 12.867910 2.460660 +v 0.623117 13.127620 2.157331 +v 1.551306 12.992560 3.170801 +v 0.000000 12.613090 -1.640317 +v 2.068450 12.693350 1.640489 +v 1.962782 12.775330 2.452683 +v 1.752323 12.986150 1.243569 +v 1.848828 12.847500 1.007843 +v 1.769802 12.830880 1.249987 +v 1.854856 12.154090 0.975675 +v 1.781275 12.096330 1.188441 +v 1.875547 11.678550 0.769012 +v 1.782986 11.625730 1.180455 +v 1.921769 11.558330 0.719338 +v 1.836753 11.494610 1.186027 +v 1.957240 11.241380 1.213604 +v 1.792182 11.172030 1.547334 +v 2.005738 10.764090 1.204343 +v 1.833028 10.705640 1.543039 +v 1.680941 10.283080 1.503554 +v 1.562612 10.629630 1.884739 +v 1.469546 10.280550 1.793877 +v 1.063391 10.256590 2.011419 +v 1.162678 9.936694 1.713143 +v 0.746678 9.906470 1.908898 +v 0.769049 9.687703 1.674452 +v 0.413612 9.578379 1.951139 +v 0.459518 9.428568 1.700112 +v 0.000000 9.515562 2.018119 +v 0.000000 9.341222 1.740110 +v -0.459518 9.428568 1.700112 +v -0.494294 9.361692 1.424746 +v -0.843751 9.628569 1.421565 +v -0.903653 9.598561 1.101898 +v -1.102326 9.678078 1.089769 +v -1.170525 9.717418 0.753059 +v -1.566268 9.959523 0.706689 +v -1.561268 10.044620 0.246017 +v -1.863951 10.401820 0.177396 +v -1.522133 10.093290 0.159468 +v -1.803192 10.448550 0.058780 +v -1.387666 10.204570 -0.299892 +v -1.605811 10.509010 -0.332389 +v -1.136660 10.241760 -0.507796 +v 1.959256 10.700680 0.067225 +v 2.088985 10.677070 -0.249337 +v 1.764856 10.938110 -0.322868 +v 2.313939 10.822330 -0.580824 +v 1.865379 11.267420 -0.596722 +v 2.531871 11.239260 -0.873608 +v 2.638484 11.637040 -0.940677 +v 2.904711 11.604470 -0.786551 +v 2.936138 11.983380 -0.696109 +v 2.902946 11.889240 -0.442240 +v 2.858504 12.301250 -0.497842 +v 2.828136 12.163640 -0.286415 +v 2.595433 12.419410 -0.161437 +v 2.627493 12.232800 -0.085955 +v 2.388068 12.324620 0.046740 +v 2.408219 12.159790 0.084515 +v 1.983673 11.835360 0.236689 +v 2.157812 11.844620 0.162071 +v 1.949521 11.528890 0.259513 +v 2.051644 11.536030 0.152832 +v 2.083566 11.299250 0.119936 +v 2.278484 11.539000 -0.301957 +v 2.184132 11.243520 -0.308903 +v 2.722009 11.261770 -0.470165 +v 2.542340 11.033690 -0.335288 +v 2.468928 10.811320 -0.513735 +v 2.233978 10.685420 -0.212374 +v 2.099445 10.689400 0.012415 +v 2.025254 10.859620 0.185335 +v -0.413612 9.578379 1.951139 +v -0.769049 9.687703 1.674452 +v -0.746678 9.906470 1.908898 +v -1.162678 9.936694 1.713143 +v -1.063391 10.256590 2.011419 +v -1.469546 10.280550 1.793877 +v -1.562612 10.629630 1.884739 +v -1.680941 10.283080 1.503554 +v -1.833028 10.705640 1.543039 +v -2.005738 10.764090 1.204343 +v -1.792182 11.172030 1.547334 +v -1.957240 11.241380 1.213604 +v -1.836753 11.494610 1.186027 +v -1.921769 11.558330 0.719338 +v -1.782986 11.625730 1.180455 +v -1.875547 11.678550 0.769012 +v -1.781275 12.096330 1.188441 +v -1.854856 12.154090 0.975675 +v -1.769802 12.830880 1.249987 +v -1.848828 12.847500 1.007843 +v -1.752323 12.986150 1.243569 +v -0.574668 11.224570 2.241889 +v -0.712694 11.162720 2.436935 +v -0.552571 10.979770 2.246094 +v -0.720952 10.918900 2.429066 +v -0.442700 10.742400 2.316571 +v -0.529992 10.608190 2.634311 +v -0.172668 10.450550 2.620517 +v -0.213127 10.383930 2.902926 +v 0.213129 10.383930 2.902926 +v -0.233421 10.374820 3.192878 +v 0.233422 10.374820 3.192878 +v -0.206868 10.455590 3.450263 +v 0.206869 10.455590 3.450263 +v -0.145738 10.642380 3.636665 +v 0.145739 10.642380 3.636665 +v -0.096213 10.830180 3.743005 +v 0.096215 10.830180 3.743005 +v 0.000001 11.118200 3.804742 +v 0.269426 10.978440 3.755978 +v 0.266678 11.173280 3.773024 +v 0.542341 11.105410 3.677175 +v 1.594081 11.568130 1.489954 +v 1.700958 11.437820 1.529107 +v 1.352015 11.487940 1.704589 +v 1.445386 11.344740 1.801978 +v 0.963445 11.351390 1.904694 +v 1.089238 11.204330 2.018752 +v 0.712741 11.102330 2.137667 +v 1.217114 10.931590 2.084295 +v 0.780739 10.813990 2.190275 +v 0.826820 10.441440 2.171478 +v 0.442701 10.742400 2.316571 +v 0.561792 10.266040 2.291410 +v 0.218727 10.241560 2.470505 +v 0.193318 10.186100 2.336314 +v 0.000000 10.211340 2.477642 +v 0.000000 10.150660 2.364559 +v -0.193318 10.186100 2.336314 +v -0.180165 10.180390 2.251199 +v -0.502502 10.201910 2.155107 +v -0.266678 11.173280 3.773024 +v -0.066461 11.314610 3.785388 +v -0.305680 11.407660 3.703619 +v -0.123466 11.469420 3.709021 +v -0.419297 11.531010 3.544350 +v -0.168584 11.615130 3.551710 +v -0.491429 11.616100 3.301477 +v -0.197185 11.713540 3.310000 +v -0.211938 11.739900 3.021558 +v 0.197187 11.713540 3.310000 +v 0.211940 11.739900 3.021558 +v 0.491430 11.616100 3.301477 +v 0.514654 11.639740 3.012797 +v 0.738851 11.428360 3.285052 +v 0.747242 11.449680 2.996168 +v 0.867464 11.145800 2.969581 +v 0.805519 11.161560 2.682721 +v -0.460986 11.291730 3.693475 +v -0.631231 11.369740 3.530241 +v -0.738850 11.428360 3.285051 +v -0.514654 11.639740 3.012797 +v -0.194569 11.714710 2.731117 +v 0.194570 11.714710 2.731117 +v 0.485353 11.618760 2.722722 +v 0.689168 11.449280 2.707893 +v 0.712695 11.162720 2.436935 +v -0.909110 9.922547 -0.272572 +v -0.905323 9.630587 0.756088 +v -0.492895 9.708358 -0.258468 +v -0.516512 9.410655 0.746993 +v 0.000000 9.347382 0.747085 +v 0.000000 9.273074 1.104929 +v 0.516512 9.410655 0.746993 +v 0.520769 9.360780 1.091756 +v 0.905323 9.630587 0.756088 +v 0.903653 9.598561 1.101898 +v 1.170525 9.717418 0.753059 +v 1.102327 9.678078 1.089769 +v 1.566268 9.959523 0.706689 +v 1.492854 9.939319 1.132486 +v 1.806870 10.285740 1.178329 +v 1.337416 9.939746 1.442987 +v -0.542340 11.105410 3.677175 +v -0.743054 11.115660 3.508012 +v -0.851418 11.130290 3.258972 +v -0.867463 11.145800 2.969581 +v -0.747241 11.449680 2.996168 +v -0.805518 11.161560 2.682721 +v -0.689167 11.449280 2.707893 +v -0.589425 11.405020 2.462541 +v -0.421208 11.563340 2.480799 +v -0.413710 11.531770 2.285545 +v -0.189585 11.664080 2.500513 +v -0.176767 11.643060 2.316026 +v 0.000000 11.668500 2.342209 +v 0.398751 12.325470 2.215086 +v 0.429505 12.527300 2.264421 +v 0.446034 12.510540 2.284310 +v 0.511151 12.750490 2.246626 +v 0.548516 12.714900 2.305280 +v 0.665010 13.010890 2.171137 +v 0.693896 12.942110 2.279652 +v 0.863072 13.170560 2.079332 +v 0.889961 13.072690 2.189679 +v 1.144239 13.146940 1.930392 +v 1.160000 13.071500 2.036463 +v 1.351307 12.969330 1.830823 +v 1.348946 12.927090 1.910008 +v 1.455859 12.666720 1.754613 +v 1.335150 12.846400 1.958474 +v 1.306832 12.779400 1.956208 +v 1.143744 12.810790 2.089009 +v -1.764856 10.938110 -0.322868 +v -1.865379 11.267420 -0.596722 +v -2.313939 10.822330 -0.580824 +v -2.531871 11.239260 -0.873608 +v -2.468928 10.811320 -0.513735 +v -2.768718 11.220620 -0.733952 +v -2.722009 11.261770 -0.470165 +v -2.866169 11.585160 -0.504026 +v -2.278484 11.539000 -0.301957 +v -2.902946 11.889240 -0.442240 +v -2.352670 11.837100 -0.240880 +v -2.828136 12.163640 -0.286415 +v -2.627493 12.232800 -0.085955 +v -2.595433 12.419410 -0.161437 +v -2.388068 12.324620 0.046740 +v -2.291891 12.349760 -0.035424 +v -1.983673 11.835360 0.236689 +v -2.088985 10.677070 -0.249337 +v -2.233978 10.685420 -0.212374 +v -2.099445 10.689400 0.012415 +v -2.356286 10.963950 -0.148784 +v -2.162447 11.047490 0.043394 +v -2.184132 11.243520 -0.308903 +v -2.083566 11.299250 0.119936 +v -2.051644 11.536030 0.152832 +v -2.157812 11.844620 0.162071 +v -1.949521 11.528890 0.259513 +v 0.176768 11.643060 2.316026 +v 0.241016 11.938080 2.223529 +v 0.000000 11.936930 2.303538 +v 0.291187 12.275920 2.244370 +v 0.000000 12.288640 2.311574 +v 0.407181 12.466980 2.261751 +v 0.000000 12.464340 2.337328 +v 0.644862 12.647260 2.236268 +v 0.000000 12.644400 2.330003 +v 0.000000 13.369440 2.171301 +v -0.644862 12.647260 2.236268 +v -0.628788 13.378360 2.069496 +v -0.930256 12.724580 2.142677 +v -0.269425 10.978440 3.755978 +v -0.366451 10.746580 3.645782 +v -0.515520 10.930790 3.661896 +v -0.514677 10.601660 3.463044 +v -0.711985 10.857940 3.485466 +v -0.803998 10.839480 3.238306 +v -0.823643 10.856400 2.949037 +v -0.808643 10.890930 2.659045 +v -0.485352 11.618760 2.722722 +v 0.189587 11.664080 2.500513 +v 0.421209 11.563340 2.480799 +v 0.589427 11.405020 2.462541 +v 0.574669 11.224570 2.241889 +v 0.493119 12.472230 2.273029 +v 0.508009 12.449000 2.221493 +v 0.643078 12.617290 2.297862 +v 0.665739 12.579790 2.221824 +v 0.763857 12.714550 2.288578 +v 0.778069 12.649210 2.213351 +v 0.953787 12.800210 2.208053 +v 0.964437 12.730680 2.133210 +v 1.128069 12.751810 2.028143 +v 1.283185 12.735060 1.932940 +v 0.468147 12.490350 2.301322 +v 0.600248 12.668500 2.333474 +v 0.732298 12.814790 2.329484 +v 0.929113 12.913540 2.247978 +v 1.161391 12.923100 2.113023 +v 2.080290 10.820620 0.707694 +v 1.899853 10.311810 0.710561 +v 1.863951 10.401820 0.177396 +v 1.561268 10.044620 0.246017 +v 1.198336 9.784797 0.440858 +v 0.909110 9.922547 -0.272572 +v 0.492895 9.708358 -0.258468 +v 0.500968 9.962949 -0.709037 +v 0.173954 9.940692 -0.762688 +v 1.669672 13.197120 1.405302 +v 1.556806 12.776510 1.655577 +v 1.595891 12.469990 1.590182 +v 1.605225 12.020710 1.508854 +v 1.599653 11.794420 1.499404 +v 1.397587 11.986480 1.734067 +v 1.374801 11.737210 1.719328 +v 1.178288 11.778660 1.813900 +v 1.155768 11.592970 1.806608 +v -0.520769 9.360780 1.091756 +v 0.000000 9.275187 1.440379 +v 0.494294 9.361692 1.424746 +v 0.843751 9.628569 1.421565 +v 0.942881 9.674681 1.418424 +v 0.534659 11.320700 1.980222 +v 0.463657 11.413680 2.027582 +v 0.388084 11.531770 2.285545 +v 0.409115 11.534890 2.074941 +v 0.296909 11.689140 2.245965 +v 0.368823 11.747000 2.094312 +v 0.348382 11.942890 2.113683 +v 0.396526 12.264440 2.141097 +v 0.556915 12.490080 2.138021 +v -2.142157 12.178580 -0.242721 +v -2.459127 12.429340 -0.306828 +v -2.111866 12.093770 -0.533583 +v -2.633158 12.330650 -0.650185 +v -2.672541 12.044660 -0.849523 +v -2.936138 11.983380 -0.696109 +v -2.638484 11.637040 -0.940677 +v -2.904711 11.604470 -0.786551 +v 0.366451 10.746580 3.645782 +v 0.515521 10.930790 3.661896 +v 0.514678 10.601660 3.463044 +v 0.711985 10.857940 3.485464 +v 0.803999 10.839480 3.238307 +v 0.851419 11.130290 3.258972 +v 0.823644 10.856400 2.949037 +v 0.808644 10.890930 2.659045 +v -0.398751 12.326560 2.214768 +v -0.508009 12.450090 2.221175 +v -0.493119 12.473320 2.272711 +v -0.643078 12.618380 2.297545 +v -0.600248 12.669600 2.333156 +v -0.732298 12.815880 2.329166 +v -0.693896 12.943200 2.279334 +v -0.889961 13.073790 2.189362 +v -0.863072 13.171650 2.079014 +v -1.144239 13.148040 1.930074 +v -1.155768 11.592970 1.806608 +v -1.140754 11.469170 1.801746 +v -1.352015 11.487940 1.704589 +v -0.963445 11.351390 1.904694 +v -1.445386 11.344740 1.801978 +v -1.089238 11.204330 2.018752 +v -1.217114 10.931590 2.084295 +v -0.712741 11.102330 2.137667 +v -0.780739 10.813990 2.190275 +v -1.899853 10.311810 0.710561 +v -1.806870 10.285740 1.178329 +v -1.492854 9.939319 1.132486 +v -1.337416 9.939746 1.442987 +v -0.942881 9.674681 1.418424 +v 0.631232 11.369740 3.530241 +v 0.419298 11.531010 3.544350 +v 0.305680 11.407660 3.703619 +v 0.123467 11.469420 3.709021 +v 0.066461 11.314610 3.785388 +v -2.080290 10.820620 0.707694 +v -2.025254 10.859620 0.185335 +v -1.959256 10.700680 0.067225 +v -1.458574 10.519830 -0.414125 +v -1.521535 11.067200 1.886360 +v -1.244634 10.544060 2.077019 +v -0.826820 10.441440 2.171478 +v 0.815985 10.062070 -0.626178 +v 1.125227 10.015610 -0.280054 +v 1.387666 10.204570 -0.299892 +v 1.522133 10.093290 0.159468 +v 1.803192 10.448550 0.058780 +v -0.665739 12.580880 2.221507 +v -0.778069 12.650300 2.213034 +v -0.763857 12.715650 2.288261 +v -0.953787 12.801300 2.207735 +v -0.929113 12.914640 2.247660 +v -1.161391 12.924190 2.112705 +v -1.160000 13.072590 2.036145 +v -1.348946 12.928180 1.909691 +v -1.351307 12.970420 1.830506 +v -1.455859 12.667820 1.754296 +v -1.178288 11.778660 1.813900 +v -1.374801 11.737210 1.719328 +v -1.397587 11.986480 1.734067 +v -1.605225 12.020710 1.508854 +v -1.388369 12.386890 1.786717 +v -1.595891 12.469990 1.590182 +v -1.205964 12.725090 1.978149 +v -1.556806 12.776510 1.655577 +v -1.391222 13.412000 1.685593 +v -1.540266 13.429660 1.483825 +v 0.552571 10.979770 2.246094 +v 0.720954 10.918900 2.429066 +v 0.529993 10.608190 2.634311 +v 0.565744 10.552580 2.917682 +v 0.872569 10.330750 1.415297 +v 0.849774 10.158600 1.400248 +v 0.705923 10.286050 1.926228 +v 0.687482 10.115070 1.897832 +v 0.394649 10.258420 2.166146 +v 0.387606 10.088160 2.129500 +v 0.000000 10.088160 2.195407 +v 0.353663 10.057660 2.023009 +v 0.000000 10.057660 2.088916 +v -0.810912 12.568480 2.053618 +v -1.039959 12.525650 1.958726 +v -1.175038 12.313990 1.866498 +v -1.200809 11.964360 1.821192 +v -0.815985 10.062070 -0.626178 +v -1.125227 10.015610 -0.280054 +v -1.198336 9.784797 0.440858 +v -0.964437 12.731780 2.132893 +v -1.143744 12.811880 2.088692 +v -1.335150 12.847490 1.958157 +v -0.407181 12.466980 2.261751 +v -0.556915 12.490080 2.138021 +v -0.291187 12.275920 2.244370 +v -0.396526 12.264440 2.141097 +v -0.348382 11.942890 2.113683 +v -0.665010 13.011980 2.170819 +v -0.548516 12.715990 2.304962 +v -0.468147 12.491440 2.301004 +v 2.142157 12.178580 -0.242721 +v 2.291891 12.349760 -0.035424 +v 2.459127 12.429340 -0.306828 +v 2.633158 12.330650 -0.650185 +v 2.018273 11.305710 0.698198 +v 1.984877 11.295760 0.236776 +v 1.140754 11.469170 1.801746 +v -0.500968 9.962949 -0.709037 +v -0.173954 9.940692 -0.762688 +v 0.000000 9.646499 -0.263641 +v -1.594081 11.568130 1.489954 +v -1.700958 11.437820 1.529107 +v 0.565326 10.540390 3.207363 +v -0.241016 11.938080 2.223529 +v -0.296909 11.689140 2.245965 +v -0.409115 11.534890 2.074941 +v -0.463657 11.413680 2.027582 +v 0.168584 11.615120 3.551709 +v 1.521535 11.067200 1.886360 +v -0.532896 10.204310 2.221562 +v -0.561792 10.266040 2.291410 +v -0.218727 10.241560 2.470505 +v 0.000000 10.454510 2.555438 +v 0.930256 12.724580 2.142677 +v 0.628788 13.378360 2.069496 +v 1.205964 12.725090 1.978149 +v 1.391222 13.412000 1.685593 +v 1.540266 13.429660 1.483825 +v -1.669672 13.197120 1.405302 +v -0.886930 10.320960 2.139071 +v -0.565743 10.552580 2.917681 +v -0.565325 10.540390 3.207363 +v 1.388369 12.386890 1.786717 +v 1.039959 12.525650 1.958726 +v 1.175038 12.313990 1.866498 +v 0.172669 10.450550 2.620517 +v 1.998262 11.610960 -0.653876 +v 2.672541 12.044660 -0.849523 +v 2.111866 12.093770 -0.533583 +v -1.998262 11.610960 -0.653876 +v 2.162447 11.047490 0.043394 +v 0.743054 11.115660 3.508012 +v 0.886930 10.320960 2.139071 +v 1.244634 10.544060 2.077019 +v 2.866169 11.585160 -0.504026 +v 2.768718 11.220620 -0.733952 +v -0.511151 12.751590 2.246308 +v -0.446034 12.511640 2.283993 +v -2.408219 12.159790 0.084515 +v -2.542340 11.033690 -0.335288 +v -2.858504 12.301250 -0.497842 +v -0.368823 11.747000 2.094312 +v -1.128069 12.752900 2.027825 +v -1.306832 12.780490 1.955890 +v 0.810912 12.568480 2.053618 +v 1.136660 10.241760 -0.507796 +v 1.605811 10.509010 -0.332389 +v 1.458574 10.519830 -0.414125 +v 0.000000 9.846251 2.136560 +v -0.287676 9.876434 2.121832 +v -0.510110 9.933239 2.050677 +v -0.872569 10.330750 1.415297 +v -0.705923 10.286050 1.926228 +v -0.849774 10.158600 1.400248 +v -0.687482 10.115070 1.897832 +v -0.739934 10.118990 1.397824 +v -0.598619 10.081080 1.831092 +v -0.394649 10.258420 2.166146 +v -0.387606 10.088160 2.129500 +v -0.353663 10.057660 2.023009 +v 0.739934 10.118990 1.397824 +v 0.598619 10.081080 1.831092 +v 0.460987 11.291730 3.693475 +v 2.352670 11.837100 -0.240880 +v 2.356286 10.963950 -0.148784 +v -1.984877 11.295760 0.236776 +v 0.748467 11.303270 1.948729 +v 1.200809 11.964360 1.821192 +v -2.018273 11.305710 0.698198 +v 0.558982 10.303170 1.299068 +v 0.276480 10.295230 1.188396 +v 0.502502 10.201910 2.155107 +v 0.180165 10.180390 2.251199 +v 1.851954 12.460420 0.873425 +v 1.849792 12.707070 0.908396 +v 0.000000 10.146290 2.263449 +v 0.287676 9.876434 2.121832 +v -0.534659 11.320700 1.980222 +v -0.748467 11.303270 1.948729 +v -0.276480 10.295230 1.188396 +v -1.849792 12.707070 0.908396 +v -1.851954 12.460420 0.873425 +v 0.000000 10.258420 2.232053 +v 0.510110 9.933239 2.050677 +v 0.532896 10.204310 2.221562 +v -0.429505 12.528400 2.264103 +v -1.283185 12.736150 1.932623 +v -0.305820 10.188010 2.218752 +v 0.000000 10.175820 2.249704 +v 0.000000 10.116600 2.322186 +v 0.305820 10.188010 2.218752 +v 0.298168 10.138290 2.282967 +v 0.587067 10.216460 2.131738 +v 0.681511 10.227410 2.093634 +v 0.739092 10.071730 2.014534 +v 0.680356 10.221940 2.102393 +v 0.000000 10.529660 1.160332 +v -0.558982 10.303170 1.299069 +v -0.739092 10.071730 2.014534 +v -0.681511 10.227410 2.093634 +v -0.587067 10.216460 2.131738 +v -0.680356 10.221940 2.102393 +v -0.298168 10.138290 2.282967 +v -0.518750 10.001240 2.125822 +v -0.539225 10.180130 2.196210 +v 0.518750 10.001240 2.125822 +v 0.288416 9.955229 2.258482 +v 0.539225 10.180130 2.196210 +v 0.000000 9.932396 2.301331 +v -0.288416 9.955229 2.258482 +v -1.510921 7.508228 1.970894 +v -1.582143 7.560649 1.896605 +v -1.544374 7.649559 2.076148 +v -1.643989 7.746365 1.961366 +v -1.432401 7.979566 2.092202 +v -1.670612 7.895855 1.864557 +v -1.619799 8.054550 1.810036 +v -1.655906 7.934601 1.657915 +v -1.612978 8.035809 1.631457 +v -1.548993 8.125335 1.624636 +v -1.509318 8.180986 1.810956 +v -1.368337 8.245316 1.867143 +v -1.233428 8.232656 1.964599 +v -1.201183 8.287729 1.765204 +v -1.118289 8.268457 1.831979 +v -0.981637 7.871101 2.151519 +v -1.160351 7.844109 2.236253 +v -1.112587 8.005334 2.178722 +v -1.139788 8.146038 2.078639 +v -1.049872 8.222912 1.904715 +v -1.021589 7.765161 2.180429 +v -1.080549 7.667704 2.188922 +v -1.266821 7.706648 2.235672 +v -1.154888 7.584133 2.179066 +v -1.241996 7.524615 2.148222 +v -0.997745 8.157707 1.978154 +v -0.969104 8.073084 2.046795 +v -0.962042 7.976151 2.106822 +v -1.406407 7.634623 2.176922 +v -1.425799 7.485507 2.040567 +v -1.471494 8.200077 1.634477 +v -1.383179 8.252689 1.663656 +v -1.291170 8.283926 1.707227 +v -1.678712 7.828974 1.699201 +v -1.670231 7.726803 1.756307 +v -1.637611 7.634083 1.823216 +v -1.334306 7.489229 2.101826 +v 1.114533 4.814950 1.377775 +v 1.156424 5.002910 1.446081 +v 1.592004 4.930693 1.196918 +v 1.624634 5.171618 1.267246 +v 1.979183 5.055533 0.935973 +v 1.979237 5.323231 0.980269 +v 2.133603 5.127602 0.380946 +v 2.129862 5.374914 0.380712 +v 0.329160 4.727600 1.275747 +v 0.438522 4.791419 1.428093 +v 0.635599 4.817656 1.381455 +v 0.596225 4.905333 1.540346 +v 1.087669 5.104812 1.644964 +v 1.630318 5.275762 1.492427 +v 0.127414 4.664594 1.014603 +v 0.296709 4.694330 0.989676 +v 1.885850 5.459831 -0.973636 +v 1.599132 5.440588 -1.376738 +v 1.568433 5.236909 -1.297687 +v 0.814291 5.208681 -1.562935 +v 0.525345 4.993155 1.725062 +v 1.018764 5.197355 1.661631 +v 1.574770 5.403075 1.491665 +v 2.003110 5.592872 1.071972 +v 2.082522 5.477250 1.024405 +v 2.200414 5.731697 0.377746 +v 2.244179 5.584166 0.383422 +v 2.171789 5.684098 -0.356859 +v 2.199239 5.524813 -0.390731 +v 1.922733 5.334917 -0.949766 +v 1.850913 5.165162 -0.937788 +v 1.572024 5.030468 -1.195917 +v 1.627479 5.003730 -1.104424 +v 0.685223 4.848284 -1.283010 +v 0.628791 4.798653 -1.149622 +v 0.310034 4.751539 -0.904914 +v 0.083224 4.673686 -0.292340 +v 0.000000 4.712549 -0.301885 +v 1.633937 5.756733 -1.408332 +v 0.868839 5.738404 -1.669444 +v 0.852042 5.446687 -1.641943 +v 0.000000 5.468840 -1.606066 +v 0.000000 5.230408 -1.532782 +v 0.765222 4.970138 -1.442486 +v 0.000000 4.956588 -1.329118 +v 0.000000 4.809403 -0.956457 +v 0.187042 4.694369 1.306379 +v 0.306662 4.829028 1.504143 +v 0.098062 4.686429 0.440568 +v 0.000000 4.667309 0.432749 +v 0.000000 4.665341 1.028676 +v 0.000000 4.697290 1.268621 +v 0.000000 4.697289 1.321063 +v 2.114877 5.282045 -0.385944 +v -1.922733 5.334917 -0.949766 +v -1.885850 5.459831 -0.973636 +v -2.199239 5.524813 -0.390731 +v -2.171789 5.684098 -0.356859 +v -2.244179 5.584166 0.383422 +v -2.200414 5.731697 0.377746 +v -1.633937 5.756733 -1.408332 +v -0.852042 5.446687 -1.641943 +v -0.868839 5.738404 -1.669444 +v 0.000000 5.722660 -1.668574 +v -0.098062 4.686429 0.440568 +v -0.127414 4.664594 1.014603 +v -0.187042 4.694369 1.306379 +v 0.000000 4.826718 1.531002 +v -0.306662 4.829028 1.504143 +v -0.083224 4.673686 -0.292340 +v -0.814291 5.208681 -1.562935 +v -1.964345 5.698889 -0.985733 +v 1.964345 5.698889 -0.985733 +v 0.657130 4.516116 -0.973189 +v 0.617991 4.660523 -1.095950 +v 0.123804 4.484560 -0.292264 +v 0.137118 4.515884 0.406839 +v 0.269309 4.603271 0.938870 +v 0.330982 4.517188 0.910432 +v 2.115681 5.095560 -0.372493 +v 1.631054 4.898668 -1.006696 +v 0.661013 4.577561 1.135031 +v 0.577180 4.692156 1.279501 +v 0.663369 3.849579 -0.970964 +v 1.487800 3.907820 -0.993038 +v 1.570851 4.693527 -1.015432 +v 1.971359 3.946729 -0.370245 +v 1.980775 4.794678 -0.372225 +v 2.000641 4.029076 0.270638 +v 2.013977 4.814626 0.331876 +v 1.849623 3.990204 0.760255 +v 1.864797 4.751930 0.848989 +v 1.497154 3.955765 0.992297 +v 1.507097 4.666272 1.081191 +v 1.099243 3.914449 1.173626 +v 1.123533 4.618333 1.260109 +v 0.718161 3.896522 1.042974 +v 0.146304 3.875505 0.347269 +v 0.126336 3.851244 -0.332229 +v 0.359529 3.867412 0.821500 +v 1.148102 2.180081 -1.190015 +v 1.748785 2.221202 -1.031061 +v 1.511722 3.041003 -0.948281 +v 2.051962 2.225689 -0.478883 +v 1.987549 3.132058 -0.408688 +v 2.091489 2.317028 0.157809 +v 2.051525 3.261630 0.241108 +v 1.909612 2.390494 0.699859 +v 1.856655 3.422008 0.715389 +v 1.515053 3.413279 0.956452 +v 1.489590 3.719428 1.031905 +v 1.128269 3.706222 1.219676 +v 1.818431 3.712188 0.792491 +v 2.110982 3.468365 0.258499 +v 2.035422 3.456234 -0.387997 +v 1.508769 3.432463 -1.124470 +v 0.177941 2.280771 0.217706 +v 0.201503 2.222157 -0.443713 +v 0.185240 3.191594 0.314337 +v 0.213260 3.095410 -0.374169 +v 0.114347 3.391347 0.337259 +v 0.148992 3.379959 -0.350675 +v 0.210442 3.577432 0.338424 +v 0.197774 3.586953 -0.346799 +v 0.569853 2.218617 -1.012292 +v 0.711593 3.026936 -0.953008 +v 0.690176 3.411932 -1.104946 +v 0.710060 3.636965 -1.013824 +v 1.468153 3.660123 -1.033540 +v 1.535731 2.467517 1.027818 +v 1.133074 3.394089 1.146498 +v 0.753913 3.695539 1.081625 +v 1.167363 2.511574 1.223167 +v 0.744457 3.393992 1.005909 +v 0.411402 3.634739 0.851898 +v 2.007700 3.691336 0.267445 +v 1.899711 3.665913 -0.382089 +v 0.385037 3.348718 0.775200 +v 0.767325 2.465782 1.061669 +v 0.414490 2.388402 0.786629 +v -0.823761 6.964651 2.374565 +v -0.647598 7.237238 2.370561 +v 0.000000 6.938833 2.493922 +v 0.000000 7.226529 2.440851 +v 0.647598 7.237238 2.370561 +v 0.000000 7.482864 2.452770 +v 0.610857 7.486744 2.357241 +v 0.000000 7.653342 2.296932 +v 0.584603 7.697172 2.248512 +v -1.574264 7.059490 -1.285800 +v -0.718160 7.089123 -1.587267 +v -1.576884 7.363946 -1.317161 +v -0.757411 7.390270 -1.623716 +v -0.764944 7.741642 -1.668800 +v 0.000000 7.406619 -1.648655 +v 0.000000 7.775780 -1.717295 +v 0.764944 7.741642 -1.668800 +v 1.574264 7.059490 -1.285800 +v 1.576884 7.363946 -1.317161 +v 0.718160 7.089123 -1.587267 +v 0.757411 7.390270 -1.623716 +v 0.000000 7.088963 -1.589592 +v -1.002800 7.359126 2.247254 +v -0.610857 7.486744 2.357241 +v 0.853312 7.771706 2.169296 +v 0.871005 7.465786 2.306669 +v 1.002800 7.359126 2.247254 +v -1.737046 7.603743 1.665858 +v -1.747599 7.355634 1.779568 +v -1.999031 7.145140 1.349625 +v -1.580330 7.033701 2.000053 +v 1.737046 7.603743 1.665858 +v 1.999031 7.145140 1.349625 +v 1.747599 7.355634 1.779568 +v 1.580330 7.033701 2.000053 +v 0.823761 6.964651 2.374565 +v -0.584603 7.697172 2.248512 +v -0.853312 7.771706 2.169296 +v -0.871005 7.465786 2.306669 +v 0.803529 9.622688 0.283393 +v 0.763946 9.657425 -0.151422 +v 0.810662 9.737752 -0.045750 +v 0.738136 9.734219 -0.440653 +v 1.313325 9.621177 -0.481966 +v 0.633945 9.573605 -0.960922 +v 1.254860 9.452376 -0.965084 +v 0.398022 9.138188 -1.392014 +v 1.190269 8.901089 -1.376694 +v 0.667922 8.451005 -1.618670 +v 1.314828 8.295366 -1.509923 +v 0.693376 9.664098 -0.617521 +v 0.663240 9.599764 -0.757944 +v 0.622645 9.508775 -0.882633 +v 0.397697 9.115714 -1.273372 +v 0.000000 8.638350 -1.643540 +v 0.000000 8.641103 -1.553166 +v -0.397697 9.115714 -1.273372 +v 0.817863 9.416183 0.798099 +v 0.815733 9.586674 0.510893 +v 0.845676 9.411090 0.948881 +v 0.847076 9.625593 0.471684 +v 1.443617 9.431608 0.522945 +v 1.364249 9.628754 -0.024216 +v 1.389311 9.530473 -0.071460 +v 1.339691 9.514383 -0.476317 +v 1.285743 9.349880 -0.929480 +v -1.564361 8.917301 0.920245 +v -1.466578 9.356601 0.474635 +v -1.545270 8.996404 0.975990 +v -1.443617 9.431608 0.522945 +v -0.865429 9.078098 1.357839 +v -0.845676 9.411090 0.948881 +v -0.829135 9.228011 1.075755 +v -0.829620 9.340392 0.844160 +v -1.389311 9.530473 -0.071460 +v -1.364249 9.628754 -0.024216 +v -0.847076 9.625593 0.471684 +v -0.810662 9.737752 -0.045750 +v -0.803529 9.622688 0.283393 +v -0.763946 9.657425 -0.151422 +v -1.339691 9.514383 -0.476317 +v -1.313325 9.621177 -0.481966 +v -0.738136 9.734219 -0.440653 +v -0.693376 9.664098 -0.617521 +v -1.285743 9.349880 -0.929480 +v -1.254860 9.452376 -0.965084 +v -0.633945 9.573605 -0.960922 +v -0.398022 9.138188 -1.392014 +v -0.622645 9.508775 -0.882633 +v 0.833126 8.957104 1.302518 +v 0.831524 9.088048 1.112448 +v 0.865429 9.078098 1.357839 +v 0.829135 9.228011 1.075755 +v 0.829620 9.340392 0.844160 +v -1.244225 8.825111 -1.284364 +v -1.190269 8.901089 -1.376694 +v -0.667922 8.451005 -1.618670 +v -0.815733 9.586674 0.510893 +v -0.663240 9.599764 -0.757944 +v -0.833126 8.957104 1.302518 +v -0.831524 9.088048 1.112448 +v 1.545270 8.996404 0.975990 +v 1.244225 8.825111 -1.284364 +v 1.466578 9.356601 0.474635 +v 1.352945 8.267432 -1.400377 +v -0.817863 9.416183 0.798099 +v -1.314828 8.295366 -1.509923 +v -1.352945 8.267432 -1.400377 +v 1.564361 8.917301 0.920245 +v 0.839899 8.240106 1.895367 +v 0.831977 8.249213 1.795377 +v 0.889841 8.320537 1.948827 +v 0.884840 8.734900 1.679775 +v -1.691858 8.094415 1.434244 +v -1.609711 8.591339 1.254444 +v -0.884840 8.734900 1.679775 +v 1.585619 7.635220 -1.223837 +v 1.749608 7.598637 -1.302808 +v 1.903092 7.416755 -0.895911 +v 2.073808 7.364027 -0.963254 +v 1.674450 8.175634 1.515584 +v 1.609711 8.591339 1.254444 +v 1.691858 8.094415 1.434244 +v -0.889841 8.320537 1.948827 +v -1.674450 8.175634 1.515584 +v -2.073808 7.364027 -0.963254 +v -1.983984 7.150850 -0.929517 +v -1.749608 7.598637 -1.302808 +v 1.983984 7.150850 -0.929517 +v -1.585619 7.635220 -1.223837 +v -1.903092 7.416755 -0.895911 +v -0.839899 8.240106 1.895367 +v -0.831977 8.249213 1.795377 +v -0.438522 4.791419 1.428093 +v -0.635599 4.817656 1.381455 +v -0.596225 4.905333 1.540346 +v -1.156424 5.002910 1.446081 +v -1.087669 5.104812 1.644964 +v -1.630318 5.275762 1.492427 +v -1.574770 5.403075 1.491665 +v -0.765222 4.970138 -1.442486 +v -1.568433 5.236909 -1.297687 +v -1.599132 5.440588 -1.376738 +v -1.114533 4.814950 1.377775 +v -1.592004 4.930693 1.196918 +v -1.624634 5.171618 1.267246 +v -1.979237 5.323231 0.980269 +v -0.296709 4.694330 0.989676 +v -0.329160 4.727600 1.275747 +v -0.525345 4.993155 1.725062 +v -1.018764 5.197355 1.661631 +v -1.979183 5.055533 0.935973 +v -2.129862 5.374914 0.380712 +v -2.133603 5.127602 0.380946 +v -0.685223 4.848284 -1.283010 +v -2.003110 5.592872 1.071972 +v -2.082522 5.477250 1.024405 +v -2.114877 5.282045 -0.385944 +v -1.850913 5.165162 -0.937788 +v -1.627479 5.003730 -1.104424 +v -1.572024 5.030468 -1.195917 +v -0.628791 4.798653 -1.149622 +v -0.310034 4.751539 -0.904914 +v 1.584343 5.520783 1.671594 +v 2.093796 6.006382 1.253015 +v 2.047222 5.731420 1.162386 +v 2.329151 6.180674 0.500840 +v 2.272855 5.892697 0.437374 +v 2.326510 6.236048 -0.318856 +v 2.267821 5.916972 -0.333258 +v 2.081320 6.297632 -0.950798 +v 2.032213 5.939744 -0.976718 +v 0.000000 6.039932 2.458880 +v 0.000000 5.535075 2.248876 +v -0.852154 6.090490 2.326676 +v -0.769615 5.582314 2.123062 +v -1.675844 6.267676 1.946933 +v -1.642547 5.840744 1.810288 +v -2.109404 6.425319 1.340365 +v -2.093796 6.006382 1.253015 +v 2.334923 6.615084 -0.292960 +v 2.342495 6.547236 0.530015 +v 2.109404 6.425319 1.340365 +v 1.642547 5.840744 1.810288 +v 0.852154 6.090490 2.326676 +v 0.769615 5.582314 2.123062 +v 0.385663 5.220873 1.908444 +v 0.952054 5.294010 1.869285 +v 1.675844 6.267676 1.946933 +v -2.334923 6.615084 -0.292960 +v -2.342495 6.547236 0.530015 +v -2.326510 6.236048 -0.318856 +v -2.329151 6.180674 0.500840 +v -2.272855 5.892697 0.437374 +v -2.047222 5.731420 1.162386 +v -1.584343 5.520783 1.671594 +v -0.952054 5.294010 1.869285 +v -2.032213 5.939744 -0.976718 +v -2.081320 6.297632 -0.950798 +v -2.267821 5.916972 -0.333258 +v 0.000000 5.165597 2.004181 +v -0.385663 5.220873 1.908444 +v -1.643092 6.354307 -1.353684 +v -1.643492 5.999996 -1.405516 +v -0.834660 6.391747 -1.607024 +v -0.864897 6.018568 -1.669540 +v 0.000000 5.970818 -1.670089 +v 0.864897 6.018568 -1.669540 +v 1.643092 6.354307 -1.353684 +v 1.643492 5.999996 -1.405516 +v 0.834660 6.391747 -1.607024 +v 0.000000 6.335492 -1.618339 +v -0.269309 4.603271 0.938870 +v -0.577180 4.692156 1.279501 +v -0.657130 4.516116 -0.973189 +v -0.123804 4.484560 -0.292264 +v -0.617991 4.660523 -1.095950 +v -1.631054 4.898668 -1.006696 +v -0.137118 4.515884 0.406839 +v -2.013977 4.814627 0.331876 +v -1.864797 4.751930 0.848989 +v -1.507096 4.666273 1.081191 +v -1.123533 4.618333 1.260109 +v -0.661013 4.577561 1.135031 +v -1.099243 3.914449 1.173626 +v -0.718161 3.896522 1.042974 +v -0.359529 3.867412 0.821500 +v -0.330982 4.517188 0.910432 +v -0.146304 3.875505 0.347269 +v -2.115681 5.095560 -0.372493 +v -1.980775 4.794678 -0.372225 +v -1.971358 3.946729 -0.370245 +v -1.570851 4.693527 -1.015432 +v -1.487800 3.907820 -0.993038 +v -0.663369 3.849579 -0.970964 +v -0.126336 3.851244 -0.332229 +v -0.710060 3.636965 -1.013824 +v -0.197774 3.586953 -0.346799 +v -0.210442 3.577432 0.338424 +v -2.007700 3.691336 0.267445 +v -1.899711 3.665913 -0.382089 +v -2.000641 4.029076 0.270638 +v -1.468153 3.660123 -1.033540 +v -0.185240 3.191594 0.314337 +v -0.114347 3.391347 0.337259 +v -0.213259 3.095410 -0.374169 +v -0.148991 3.379959 -0.350675 +v -0.711592 3.026936 -0.953008 +v -0.690176 3.411932 -1.104946 +v -1.511721 3.041003 -0.948281 +v -1.508769 3.432463 -1.124470 +v -1.987548 3.132057 -0.408688 +v -2.035422 3.456234 -0.387997 +v -2.051525 3.261630 0.241108 +v -2.110982 3.468365 0.258499 +v -1.497154 3.955765 0.992297 +v -1.849623 3.990204 0.760255 +v -0.177941 2.280771 0.217706 +v -0.201503 2.222157 -0.443713 +v -0.569853 2.218617 -1.012292 +v -1.148102 2.180081 -1.190015 +v -1.748785 2.221202 -1.031061 +v -2.051962 2.225689 -0.478883 +v -1.818431 3.712188 0.792491 +v -1.856655 3.422008 0.715389 +v -1.909612 2.390494 0.699859 +v -2.091489 2.317028 0.157809 +v -1.489590 3.719428 1.031905 +v -1.515053 3.413279 0.956452 +v -1.535731 2.467517 1.027818 +v -1.128269 3.706222 1.219676 +v -1.133074 3.394089 1.146498 +v -1.167363 2.511574 1.223167 +v -0.753913 3.695539 1.081625 +v -0.744457 3.393992 1.005909 +v -0.767325 2.465782 1.061669 +v -0.411402 3.634739 0.851898 +v -0.385037 3.348718 0.775200 +v -0.414490 2.388402 0.786629 +v 0.042802 1.405978 0.226746 +v 0.061077 1.845364 0.186812 +v 0.287818 1.613645 1.036232 +v 0.310346 1.998289 0.860853 +v 0.665719 1.770387 1.385350 +v 0.661022 2.091819 1.128492 +v 1.179093 1.859289 1.556835 +v 1.168076 2.166217 1.294371 +v 1.685547 1.800214 1.356417 +v 1.673007 2.118914 1.102140 +v 2.095062 1.625426 0.927504 +v 2.065772 2.005114 0.748538 +v 2.332485 1.437313 0.214883 +v 2.298291 1.886270 0.143345 +v 2.241258 1.281512 -0.529778 +v 2.207321 1.797832 -0.559381 +v 1.890434 1.771662 -1.142471 +v 1.168831 1.767884 -1.435731 +v 0.423039 1.764753 -1.133773 +v -2.207321 1.797832 -0.559381 +v -1.890434 1.771662 -1.142471 +v -1.168831 1.767884 -1.435731 +v -1.177144 1.258245 -1.468794 +v -0.411085 1.242446 -1.172871 +v -0.130782 1.267421 -0.559384 +v -0.116582 1.788120 -0.584437 +v -0.423039 1.764753 -1.133773 +v -0.042802 1.405978 0.226746 +v -0.287818 1.613644 1.036232 +v -0.061077 1.845364 0.186812 +v -0.310346 1.998289 0.860853 +v -0.665718 1.770386 1.385350 +v -0.661022 2.091819 1.128492 +v -1.179093 1.859289 1.556835 +v -1.168076 2.166217 1.294371 +v -1.685547 1.800214 1.356417 +v -1.673007 2.118914 1.102140 +v -2.095062 1.625426 0.927504 +v -2.065772 2.005114 0.748538 +v -2.332485 1.437313 0.214883 +v -2.298291 1.886270 0.143345 +v -2.241257 1.281511 -0.529778 +v 0.411085 1.242446 -1.172871 +v 0.116582 1.788120 -0.584437 +v 0.130782 1.267421 -0.559384 +v -1.210951 1.058173 0.232247 +v -1.911865 1.252236 -1.176824 +v 1.911865 1.252237 -1.176824 +v 1.210951 1.058174 0.232247 +v 1.177144 1.258245 -1.468794 +v 0.000000 6.550032 2.521446 +v 0.843099 6.600545 2.404743 +v 1.634386 6.733228 2.002429 +v 2.075220 6.870069 1.379951 +v 2.165966 7.058311 0.925038 +v 2.293922 6.941714 0.488867 +v 2.232176 7.127987 0.283413 +v 2.221925 7.086338 -0.329151 +v 2.321480 7.265271 -0.342354 +v -1.342528 7.112473 2.146200 +v -0.843099 6.600545 2.404743 +v -0.920287 7.527419 2.384719 +v -1.382063 7.179729 2.216117 +v -1.769583 7.413612 1.870816 +v -1.753190 7.678541 1.771445 +v -1.692680 8.043209 1.495212 +v -2.069922 6.662683 -0.910120 +v -2.007387 6.975141 -0.907098 +v -2.281446 6.932686 -0.313226 +v -2.293922 6.941714 0.488867 +v -2.221925 7.086338 -0.329151 +v -2.232176 7.127987 0.283413 +v -2.321480 7.265271 -0.342354 +v -2.346528 7.320678 0.194703 +v -1.634386 6.733228 2.002429 +v -2.075220 6.870069 1.379951 +v -2.165966 7.058311 0.925038 +v -2.144411 7.231871 0.793956 +v 2.069922 6.662683 -0.910121 +v 2.007387 6.975141 -0.907098 +v 2.281446 6.932686 -0.313226 +v 1.692680 8.043209 1.495212 +v 1.753190 7.678541 1.771445 +v 0.904200 7.812844 2.266071 +v 2.346528 7.320678 0.194703 +v 2.144411 7.231871 0.793956 +v 2.264602 7.413300 0.665157 +v 2.011544 7.342014 1.242110 +v 2.053965 7.610735 1.234929 +v -0.904200 7.812844 2.266071 +v 1.769583 7.413612 1.870816 +v 0.920287 7.527419 2.384719 +v 1.382063 7.179729 2.216117 +v 0.000000 8.118139 2.090904 +v 0.000000 8.126963 1.966566 +v 0.574415 8.180808 1.999622 +v 0.546090 8.180715 1.880842 +v 2.098186 7.367910 0.188199 +v 2.075356 7.331665 -0.331779 +v -2.264602 7.413300 0.665157 +v -2.011544 7.342014 1.242110 +v 1.342528 7.112473 2.146200 +v -2.053965 7.610735 1.234929 +v -2.075356 7.331665 -0.331779 +v -2.098186 7.367910 0.188199 +v -2.071481 7.453075 0.639595 +v -0.574415 8.180808 1.999622 +v 1.954920 7.633939 1.121605 +v 2.071481 7.453075 0.639595 +v -0.546090 8.180715 1.880842 +v -1.954920 7.633939 1.121605 +v -1.603881 6.714523 -1.311235 +v -0.755574 6.750603 -1.571215 +v 0.000000 6.749732 -1.573757 +v 0.755574 6.750603 -1.571215 +v 1.603881 6.714523 -1.311235 +v 1.021589 7.765161 2.180429 +v 0.981637 7.871101 2.151519 +v 1.160351 7.844109 2.236253 +v 1.112587 8.005334 2.178722 +v 1.432401 7.979566 2.092202 +v 1.139788 8.146038 2.078639 +v 1.233428 8.232656 1.964599 +v 1.049872 8.222912 1.904715 +v 1.118289 8.268457 1.831979 +v 1.201183 8.287730 1.765203 +v 1.368337 8.245316 1.867143 +v 1.509318 8.180986 1.810956 +v 1.619799 8.054550 1.810036 +v 1.548993 8.125335 1.624636 +v 1.612978 8.035809 1.631457 +v 1.655906 7.934601 1.657915 +v 1.670612 7.895855 1.864557 +v 1.643989 7.746365 1.961366 +v 1.544374 7.649559 2.076148 +v 1.582143 7.560649 1.896605 +v 1.291170 8.283927 1.707227 +v 1.383179 8.252691 1.663655 +v 1.471494 8.200077 1.634477 +v 1.678712 7.828974 1.699201 +v 1.670231 7.726803 1.756307 +v 1.637611 7.634083 1.823216 +v 1.080549 7.667704 2.188922 +v 1.266821 7.706648 2.235672 +v 1.154888 7.584133 2.179066 +v 1.241996 7.524615 2.148222 +v 1.406407 7.634623 2.176922 +v 1.334306 7.489229 2.101826 +v 1.425799 7.485507 2.040567 +v 1.510921 7.508228 1.970894 +v 0.997745 8.157707 1.978154 +v 0.969104 8.073084 2.046795 +v 0.962042 7.976151 2.106822 +v 0.963445 11.351390 1.904694 +v 0.748467 11.303270 1.948729 +v 0.769990 11.541070 2.028426 +v 0.552279 11.536260 2.085979 +v 0.555944 11.733580 2.113685 +v 0.368823 11.747000 2.094312 +v 0.550307 11.930890 2.141390 +v 0.348382 11.942890 2.113683 +v 0.396526 12.264440 2.141097 +v 0.779356 11.739150 2.056127 +v 0.788723 11.937240 2.083828 +v 1.039870 11.949460 1.963098 +v 0.788122 12.320210 2.087050 +v 1.030657 12.324680 1.970428 +v 1.039959 12.525650 1.958726 +v 1.175038 12.313990 1.866498 +v 1.178288 11.778660 1.813900 +v 1.155768 11.592970 1.806608 +v 1.025173 11.760610 1.950262 +v 1.010475 11.571770 1.937427 +v 1.140754 11.469170 1.801746 +v 1.200809 11.964360 1.821192 +v 0.556915 12.490080 2.138021 +v 0.551464 12.286460 2.156465 +v 0.409115 11.534890 2.074941 +v 0.463657 11.413680 2.027582 +v 0.534659 11.320700 1.980222 +v 0.810912 12.568480 2.053618 +v -0.963445 11.351390 1.904694 +v -0.748467 11.303270 1.948729 +v -0.769990 11.541070 2.028426 +v -0.552279 11.536260 2.085979 +v -0.555944 11.733580 2.113685 +v -0.368823 11.747000 2.094312 +v -0.550307 11.930890 2.141390 +v -0.348382 11.942890 2.113683 +v -0.396526 12.264440 2.141097 +v -0.779356 11.739150 2.056127 +v -0.788723 11.937240 2.083828 +v -1.039870 11.949460 1.963098 +v -0.788122 12.320210 2.087050 +v -1.030657 12.324680 1.970428 +v -1.039959 12.525650 1.958726 +v -1.175038 12.313990 1.866498 +v -1.178288 11.778660 1.813900 +v -1.155768 11.592970 1.806608 +v -1.025173 11.760610 1.950262 +v -1.010475 11.571770 1.937427 +v -1.140754 11.469170 1.801746 +v -1.200809 11.964360 1.821192 +v -0.556915 12.490080 2.138021 +v -0.551464 12.286460 2.156465 +v -0.409115 11.534890 2.074941 +v -0.463657 11.413680 2.027582 +v -0.534659 11.320700 1.980222 +v -0.810912 12.568480 2.053618 +vt 0.243131 0.655947 +vt 0.238403 0.660810 +vt 0.243100 0.700083 +vt 0.238773 0.637996 +vt 0.239621 0.639410 +vt 0.237167 0.626310 +vt 0.238806 0.622268 +vt 0.236501 0.604771 +vt 0.227783 0.620581 +vt 0.227607 0.609439 +vt 0.228338 0.612392 +vt 0.229615 0.601353 +vt 0.229904 0.607124 +vt 0.233150 0.599264 +vt 0.232536 0.605955 +vt 0.234945 0.610245 +vt 0.231888 0.617812 +vt 0.234284 0.632384 +vt 0.228327 0.623060 +vt 0.230543 0.634953 +vt 0.230660 0.633204 +vt 0.229062 0.626020 +vt 0.225100 0.627743 +vt 0.225577 0.631483 +vt 0.224185 0.639783 +vt 0.227771 0.640522 +vt 0.224594 0.650461 +vt 0.228722 0.661020 +vt 0.223970 0.650912 +vt 0.227951 0.660994 +vt 0.238403 0.660810 +vt 0.243131 0.655947 +vt 0.243100 0.700083 +vt 0.238773 0.637996 +vt 0.243131 0.655947 +vt 0.238403 0.660810 +vt 0.236106 0.643545 +vt 0.238773 0.637996 +vt 0.238403 0.660810 +vt 0.234284 0.632384 +vt 0.238773 0.637996 +vt 0.232985 0.647381 +vt 0.234284 0.632384 +vt 0.230543 0.634953 +vt 0.234284 0.632384 +vt 0.227771 0.640522 +vt 0.230543 0.634953 +vt 0.228819 0.630748 +vt 0.230543 0.634953 +vt 0.227771 0.640522 +vt 0.225577 0.631483 +vt 0.227771 0.640522 +vt 0.229062 0.626020 +vt 0.225577 0.631483 +vt 0.225100 0.627743 +vt 0.229062 0.626020 +vt 0.225577 0.631483 +vt 0.230660 0.633204 +vt 0.229062 0.626020 +vt 0.225100 0.627743 +vt 0.223416 0.637887 +vt 0.230660 0.633204 +vt 0.225100 0.627743 +vt 0.223970 0.650912 +vt 0.230660 0.633204 +vt 0.224185 0.639783 +vt 0.223970 0.650912 +vt 0.224594 0.650461 +vt 0.223970 0.650912 +vt 0.224185 0.639783 +vt 0.227771 0.640522 +vt 0.224594 0.650461 +vt 0.224185 0.639783 +vt 0.228722 0.661020 +vt 0.224594 0.650461 +vt 0.227771 0.640522 +vt 0.230853 0.653785 +vt 0.228722 0.661020 +vt 0.227771 0.640522 +vt 0.231752 0.677752 +vt 0.228722 0.661020 +vt 0.233618 0.672882 +vt 0.234920 0.700095 +vt 0.238403 0.660810 +vt 0.243100 0.700083 +vt 0.238403 0.660810 +vt 0.238773 0.637996 +vt 0.239621 0.639410 +vt 0.243131 0.655947 +vt 0.237167 0.626310 +vt 0.239621 0.639410 +vt 0.238773 0.637996 +vt 0.234284 0.632384 +vt 0.237167 0.626310 +vt 0.238773 0.637996 +vt 0.234945 0.610245 +vt 0.237167 0.626310 +vt 0.234284 0.632384 +vt 0.231888 0.617812 +vt 0.234945 0.610245 +vt 0.234284 0.632384 +vt 0.232536 0.605955 +vt 0.234945 0.610245 +vt 0.231888 0.617812 +vt 0.229904 0.607124 +vt 0.232536 0.605955 +vt 0.231888 0.617812 +vt 0.233150 0.599264 +vt 0.232536 0.605955 +vt 0.229904 0.607124 +vt 0.229615 0.601353 +vt 0.233150 0.599264 +vt 0.229904 0.607124 +vt 0.227607 0.609439 +vt 0.233150 0.599264 +vt 0.229615 0.601353 +vt 0.228338 0.612392 +vt 0.227607 0.609439 +vt 0.229615 0.601353 +vt 0.227783 0.620581 +vt 0.227607 0.609439 +vt 0.228338 0.612392 +vt 0.228327 0.623060 +vt 0.227783 0.620581 +vt 0.228338 0.612392 +vt 0.230660 0.633204 +vt 0.227783 0.620581 +vt 0.228327 0.623060 +vt 0.230543 0.634953 +vt 0.230660 0.633204 +vt 0.228327 0.623060 +vt 0.229062 0.626020 +vt 0.230660 0.633204 +vt 0.230543 0.634953 +vt 0.229062 0.626020 +vt 0.230543 0.634953 +vt 0.292253 0.594325 +vt 0.288869 0.609994 +vt 0.285485 0.594325 +vt 0.295871 0.614223 +vt 0.301089 0.609728 +vt 0.301453 0.616643 +vt 0.306547 0.618755 +vt 0.306171 0.630229 +vt 0.307710 0.635953 +vt 0.304550 0.647416 +vt 0.310423 0.656822 +vt 0.316969 0.669026 +vt 0.325655 0.678869 +vt 0.327860 0.715838 +vt 0.327737 0.683314 +vt 0.329946 0.705627 +vt 0.298613 0.595773 +vt 0.305709 0.611968 +vt 0.316941 0.623626 +vt 0.313454 0.636135 +vt 0.319930 0.626074 +vt 0.318250 0.645504 +vt 0.323789 0.643405 +vt 0.321572 0.661397 +vt 0.321631 0.641335 +vt 0.325152 0.665610 +vt 0.323197 0.649641 +vt 0.296891 0.701016 +vt 0.297901 0.698266 +vt 0.297796 0.701016 +vt 0.296891 0.698266 +vt 0.297901 0.698266 +vt 0.297908 0.695230 +vt 0.297901 0.698266 +vt 0.298736 0.698267 +vt 0.297901 0.698266 +vt 0.298748 0.695231 +vt 0.299325 0.698268 +vt 0.299270 0.695234 +vt 0.299477 0.698269 +vt 0.299434 0.694861 +vt 0.307710 0.635953 +vt 0.305709 0.611968 +vt 0.306547 0.618755 +vt 0.316941 0.623626 +vt 0.305709 0.611968 +vt 0.307710 0.635953 +vt 0.313454 0.636135 +vt 0.316941 0.623626 +vt 0.307710 0.635953 +vt 0.319930 0.626074 +vt 0.316941 0.623626 +vt 0.313454 0.636135 +vt 0.318250 0.645504 +vt 0.319930 0.626074 +vt 0.313454 0.636135 +vt 0.323789 0.643405 +vt 0.319930 0.626074 +vt 0.318250 0.645504 +vt 0.321572 0.661397 +vt 0.323789 0.643405 +vt 0.318250 0.645504 +vt 0.321631 0.641335 +vt 0.323789 0.643405 +vt 0.321572 0.661397 +vt 0.325152 0.665610 +vt 0.321631 0.641335 +vt 0.321572 0.661397 +vt 0.323197 0.649641 +vt 0.321631 0.641335 +vt 0.325152 0.665610 +vt 0.292253 0.594325 +vt 0.301089 0.609728 +vt 0.298613 0.595773 +vt 0.295871 0.614223 +vt 0.301089 0.609728 +vt 0.292253 0.594325 +vt 0.295871 0.614223 +vt 0.292253 0.594325 +vt 0.288869 0.623953 +vt 0.295871 0.614223 +vt 0.295518 0.627399 +vt 0.300287 0.634182 +vt 0.295518 0.627399 +vt 0.294388 0.645638 +vt 0.295871 0.614223 +vt 0.295518 0.627399 +vt 0.301453 0.616643 +vt 0.295871 0.614223 +vt 0.295518 0.627399 +vt 0.301089 0.609728 +vt 0.295871 0.614223 +vt 0.301453 0.616643 +vt 0.306547 0.618755 +vt 0.301089 0.609728 +vt 0.301453 0.616643 +vt 0.298613 0.595773 +vt 0.301089 0.609728 +vt 0.306547 0.618755 +vt 0.305709 0.611968 +vt 0.298613 0.595773 +vt 0.306547 0.618755 +vt 0.304741 0.601454 +vt 0.298613 0.595773 +vt 0.305709 0.611968 +vt 0.316186 0.611512 +vt 0.305709 0.611968 +vt 0.306171 0.630229 +vt 0.306547 0.618755 +vt 0.301453 0.616643 +vt 0.307710 0.635953 +vt 0.306547 0.618755 +vt 0.306171 0.630229 +vt 0.304550 0.647416 +vt 0.307710 0.635953 +vt 0.306171 0.630229 +vt 0.310423 0.656822 +vt 0.307710 0.635953 +vt 0.304550 0.647416 +vt 0.316969 0.669026 +vt 0.310423 0.656822 +vt 0.304550 0.647416 +vt 0.325655 0.678869 +vt 0.310423 0.656822 +vt 0.316969 0.669026 +vt 0.327860 0.715838 +vt 0.325655 0.678869 +vt 0.316969 0.669026 +vt 0.327737 0.683314 +vt 0.325655 0.678869 +vt 0.327860 0.715838 +vt 0.247268 0.715192 +vt 0.247793 0.700074 +vt 0.231396 0.715193 +vt 0.234920 0.700095 +vt 0.229404 0.702937 +vt 0.234920 0.700095 +vt 0.231571 0.691806 +vt 0.234920 0.700095 +vt 0.230921 0.691796 +vt 0.231141 0.677737 +vt 0.231396 0.715193 +vt 0.243100 0.700083 +vt 0.229404 0.702937 +vt 0.231396 0.715193 +vt 0.225224 0.715193 +vt 0.229404 0.702937 +vt 0.231396 0.715193 +vt 0.224609 0.709192 +vt 0.229404 0.702937 +vt 0.222321 0.712340 +vt 0.224240 0.708099 +vt 0.222398 0.711537 +vt 0.236106 0.643545 +vt 0.236106 0.643545 +vt 0.232985 0.647381 +vt 0.236106 0.643545 +vt 0.230921 0.691796 +vt 0.229404 0.702937 +vt 0.228801 0.700192 +vt 0.231571 0.691806 +vt 0.229404 0.702937 +vt 0.230921 0.691796 +vt 0.231141 0.677737 +vt 0.231571 0.691806 +vt 0.230921 0.691796 +vt 0.231571 0.691806 +vt 0.231141 0.677737 +vt 0.227951 0.660994 +vt 0.231141 0.677737 +vt 0.228722 0.661020 +vt 0.227951 0.660994 +vt 0.225224 0.715193 +vt 0.224609 0.709192 +vt 0.225224 0.715193 +vt 0.224240 0.708099 +vt 0.224609 0.709192 +vt 0.222321 0.712340 +vt 0.224609 0.709192 +vt 0.224240 0.708099 +vt 0.222398 0.711537 +vt 0.222321 0.712340 +vt 0.224240 0.708099 +vt 0.221443 0.715192 +vt 0.222321 0.712340 +vt 0.222398 0.711537 +vt 0.319293 0.715793 +vt 0.305919 0.662734 +vt 0.305529 0.715784 +vt 0.288869 0.659900 +vt 0.288869 0.715783 +vt 0.305529 0.715784 +vt 0.317239 0.625221 +vt 0.321631 0.641335 +vt 0.323197 0.649641 +vt 0.323331 0.627267 +vt 0.321631 0.641335 +vt 0.320599 0.619805 +vt 0.305709 0.611968 +vt 0.316941 0.623626 +vt 0.305709 0.611968 +vt 0.234920 0.700095 +vt 0.233618 0.672882 +vt 0.234920 0.700095 +vt 0.232985 0.647381 +vt 0.233618 0.672882 +vt 0.230853 0.653785 +vt 0.233618 0.672882 +vt 0.232985 0.647381 +vt 0.230853 0.653785 +vt 0.232985 0.647381 +vt 0.230853 0.653785 +vt 0.228327 0.623060 +vt 0.234284 0.632384 +vt 0.230543 0.634953 +vt 0.231888 0.617812 +vt 0.234284 0.632384 +vt 0.228327 0.623060 +vt 0.228338 0.612392 +vt 0.231888 0.617812 +vt 0.228327 0.623060 +vt 0.229904 0.607124 +vt 0.231888 0.617812 +vt 0.228338 0.612392 +vt 0.229615 0.601353 +vt 0.229904 0.607124 +vt 0.228338 0.612392 +vt 0.316969 0.669026 +vt 0.319293 0.715793 +vt 0.327860 0.715838 +vt 0.305919 0.662734 +vt 0.319293 0.715793 +vt 0.316969 0.669026 +vt 0.304550 0.647416 +vt 0.305919 0.662734 +vt 0.316969 0.669026 +vt 0.305919 0.662734 +vt 0.304550 0.647416 +vt 0.304550 0.647416 +vt 0.299427 0.701017 +vt 0.299241 0.701017 +vt 0.298630 0.701016 +vt 0.297901 0.698266 +vt 0.299477 0.698269 +vt 0.299270 0.695234 +vt 0.299434 0.694861 +vt 0.299325 0.698268 +vt 0.299270 0.695234 +vt 0.299477 0.698269 +vt 0.299427 0.701017 +vt 0.299325 0.698268 +vt 0.299477 0.698269 +vt 0.299241 0.701017 +vt 0.299325 0.698268 +vt 0.299427 0.701017 +vt 0.232985 0.647381 +vt 0.228819 0.630748 +vt 0.228819 0.630748 +vt 0.228819 0.630748 +vt 0.317239 0.625221 +vt 0.323331 0.627267 +vt 0.317239 0.625221 +vt 0.323331 0.627267 +vt 0.323331 0.627267 +vt 0.323331 0.627267 +vt 0.316186 0.611512 +vt 0.317239 0.625221 +vt 0.320599 0.619805 +vt 0.316186 0.611512 +vt 0.323331 0.627267 +vt 0.320599 0.619805 +vt 0.323331 0.627267 +vt 0.320599 0.619805 +vt 0.319930 0.626074 +vt 0.316941 0.623626 +vt 0.319930 0.626074 +vt 0.323789 0.643405 +vt 0.319930 0.626074 +vt 0.321631 0.641335 +vt 0.323789 0.643405 +vt 0.236501 0.604771 +vt 0.237167 0.626310 +vt 0.234945 0.610245 +vt 0.238806 0.622268 +vt 0.237167 0.626310 +vt 0.236501 0.604771 +vt 0.227783 0.620581 +vt 0.238806 0.622268 +vt 0.236501 0.604771 +vt 0.230660 0.633204 +vt 0.238806 0.622268 +vt 0.227783 0.620581 +vt 0.233150 0.599264 +vt 0.234945 0.610245 +vt 0.232536 0.605955 +vt 0.236501 0.604771 +vt 0.234945 0.610245 +vt 0.233150 0.599264 +vt 0.227607 0.609439 +vt 0.236501 0.604771 +vt 0.233150 0.599264 +vt 0.227783 0.620581 +vt 0.236501 0.604771 +vt 0.227607 0.609439 +vt 0.299325 0.698268 +vt 0.298748 0.695231 +vt 0.299270 0.695234 +vt 0.298736 0.698267 +vt 0.298748 0.695231 +vt 0.299325 0.698268 +vt 0.299241 0.701017 +vt 0.298736 0.698267 +vt 0.299325 0.698268 +vt 0.298630 0.701016 +vt 0.298736 0.698267 +vt 0.299241 0.701017 +vt 0.298736 0.698267 +vt 0.297908 0.695230 +vt 0.298748 0.695231 +vt 0.297908 0.695230 +vt 0.298736 0.698267 +vt 0.298630 0.701016 +vt 0.298736 0.698267 +vt 0.298630 0.701016 +vt 0.223416 0.637887 +vt 0.223416 0.637887 +vt 0.223416 0.637887 +vt 0.231752 0.677752 +vt 0.233618 0.672882 +vt 0.230853 0.653785 +vt 0.234920 0.700095 +vt 0.233618 0.672882 +vt 0.231752 0.677752 +vt 0.234920 0.700095 +vt 0.231752 0.677752 +vt 0.297908 0.695230 +vt 0.296891 0.695230 +vt 0.297908 0.695230 +vt 0.321572 0.661397 +vt 0.327737 0.683314 +vt 0.325152 0.665610 +vt 0.325655 0.678869 +vt 0.327737 0.683314 +vt 0.321572 0.661397 +vt 0.310423 0.656822 +vt 0.325655 0.678869 +vt 0.321572 0.661397 +vt 0.300287 0.634182 +vt 0.306171 0.630229 +vt 0.301453 0.616643 +vt 0.304550 0.647416 +vt 0.306171 0.630229 +vt 0.300287 0.634182 +vt 0.304550 0.647416 +vt 0.300287 0.634182 +vt 0.294388 0.645638 +vt 0.294388 0.645638 +vt 0.284257 0.645679 +vt 0.294388 0.645638 +vt 0.227771 0.640522 +vt 0.238403 0.660810 +vt 0.224185 0.639783 +vt 0.225577 0.631483 +vt 0.227771 0.640522 +vt 0.225100 0.627743 +vt 0.225577 0.631483 +vt 0.224185 0.639783 +vt 0.225100 0.627743 +vt 0.224185 0.639783 +vt 0.223970 0.650912 +vt 0.227951 0.660994 +vt 0.230660 0.633204 +vt 0.228722 0.661020 +vt 0.227951 0.660994 +vt 0.223970 0.650912 +vt 0.224594 0.650461 +vt 0.228722 0.661020 +vt 0.223970 0.650912 +vt 0.329946 0.705627 +vt 0.327860 0.715838 +vt 0.330536 0.711394 +vt 0.327737 0.683314 +vt 0.327860 0.715838 +vt 0.329946 0.705627 +vt 0.232985 0.647381 +vt 0.236106 0.643545 +vt 0.232985 0.647381 +vt 0.318250 0.645504 +vt 0.310423 0.656822 +vt 0.321572 0.661397 +vt 0.313454 0.636135 +vt 0.310423 0.656822 +vt 0.318250 0.645504 +vt 0.307441 0.682732 +vt 0.314866 0.705777 +vt 0.314815 0.688690 +vt 0.307594 0.710874 +vt 0.305529 0.715784 +vt 0.305919 0.662734 +vt 0.319293 0.715793 +vt 0.305919 0.662734 +vt 0.305529 0.715784 +vt 0.295518 0.627399 +vt 0.300287 0.634182 +vt 0.301453 0.616643 +vt 0.300287 0.634182 +vt 0.295518 0.627399 +vt 0.294388 0.645638 +vt 0.294388 0.645638 +vt 0.228801 0.700192 +vt 0.224240 0.708099 +vt 0.228801 0.700192 +vt 0.225224 0.715193 +vt 0.222321 0.712340 +vt 0.224609 0.709192 +vt 0.222321 0.712340 +vt 0.225224 0.715193 +vt 0.247268 0.715192 +vt 0.243100 0.700083 +vt 0.247793 0.700074 +vt 0.231396 0.715193 +vt 0.243100 0.700083 +vt 0.247268 0.715192 +vt 0.297796 0.701016 +vt 0.297901 0.698266 +vt 0.297901 0.698266 +vt 0.297796 0.701016 +vt 0.314866 0.705777 +vt 0.307441 0.682732 +vt 0.314815 0.688690 +vt 0.307594 0.710874 +vt 0.307441 0.682732 +vt 0.314866 0.705777 +vt 0.221443 0.715192 +vt 0.221443 0.715192 +vt 0.229404 0.702937 +vt 0.229404 0.702937 +vt 0.320599 0.619805 +vt 0.316186 0.611512 +vt 0.320599 0.619805 +vt 0.304741 0.601454 +vt 0.316186 0.611512 +vt 0.304741 0.601454 +vt 0.231571 0.691806 +vt 0.229404 0.702937 +vt 0.231571 0.691806 +vt 0.231752 0.677752 +vt 0.230853 0.653785 +vt 0.231752 0.677752 +vt 0.231752 0.677752 +vt 0.231752 0.677752 +vt 0.243344 0.675418 +vt 0.242563 0.655225 +vt 0.243293 0.658332 +vt 0.330536 0.711394 +vt 0.243344 0.675418 +vt 0.243293 0.658332 +vt 0.242563 0.655225 +vt 0.223416 0.637887 +vt 0.228819 0.630748 +vt 0.307710 0.635953 +vt 0.310423 0.656822 +vt 0.313454 0.636135 +vt 0.294388 0.645638 +vt 0.238403 0.660810 +vt 0.238806 0.622268 +vt 0.239621 0.639410 +vt 0.237167 0.626310 +vt 0.193937 0.930962 +vt 0.200375 0.939944 +vt 0.200525 0.930736 +vt 0.193898 0.940786 +vt 0.186536 0.929962 +vt 0.186590 0.940223 +vt 0.179120 0.930972 +vt 0.179078 0.940843 +vt 0.172090 0.930750 +vt 0.172037 0.940043 +vt 0.186539 0.920029 +vt 0.193963 0.920208 +vt 0.179104 0.920435 +vt 0.172027 0.922441 +vt 0.153653 0.936535 +vt 0.163016 0.935852 +vt 0.162973 0.943792 +vt 0.163048 0.928211 +vt 0.153644 0.916930 +vt 0.163162 0.908601 +vt 0.153624 0.875007 +vt 0.163275 0.873028 +vt 0.143363 0.936535 +vt 0.143363 0.879940 +vt 0.227036 0.936751 +vt 0.217259 0.876626 +vt 0.227026 0.879940 +vt 0.216489 0.936560 +vt 0.193963 0.920208 +vt 0.194021 0.897027 +vt 0.200581 0.923264 +vt 0.186546 0.898576 +vt 0.193963 0.920208 +vt 0.186539 0.920029 +vt 0.193963 0.920208 +vt 0.179072 0.898666 +vt 0.186539 0.920029 +vt 0.179104 0.920435 +vt 0.186539 0.920029 +vt 0.171849 0.900852 +vt 0.179104 0.920435 +vt 0.172027 0.922441 +vt 0.179104 0.920435 +vt 0.208991 0.885973 +vt 0.209032 0.920106 +vt 0.209050 0.935880 +vt 0.200740 0.902185 +vt 0.172090 0.930750 +vt 0.172027 0.922441 +vt 0.172090 0.930750 +vt 0.172027 0.922441 +vt 0.172027 0.922441 +vt 0.200525 0.930736 +vt 0.200898 0.881107 +vt 0.153624 0.875007 +vt 0.143363 0.869357 +vt 0.143363 0.879940 +vt 0.153620 0.865420 +vt 0.153624 0.875007 +vt 0.163275 0.873028 +vt 0.153624 0.875007 +vt 0.163311 0.864364 +vt 0.163275 0.873028 +vt 0.171670 0.875272 +vt 0.163275 0.873028 +vt 0.171587 0.864228 +vt 0.179040 0.876896 +vt 0.179023 0.865367 +vt 0.186552 0.877123 +vt 0.186555 0.867048 +vt 0.194078 0.873847 +vt 0.194104 0.863247 +vt 0.200898 0.881107 +vt 0.200983 0.869752 +vt 0.200898 0.881107 +vt 0.208991 0.885973 +vt 0.200898 0.881107 +vt 0.208973 0.870845 +vt 0.208991 0.885973 +vt 0.217259 0.876626 +vt 0.208991 0.885973 +vt 0.217409 0.864958 +vt 0.217259 0.876626 +vt 0.227026 0.879940 +vt 0.217259 0.876626 +vt 0.227026 0.869357 +vt 0.227026 0.879940 +vt 0.143432 0.857319 +vt 0.153616 0.857133 +vt 0.163344 0.856449 +vt 0.171522 0.855699 +vt 0.179007 0.855211 +vt 0.186559 0.854939 +vt 0.194075 0.855219 +vt 0.194012 0.844397 +vt 0.201188 0.843044 +vt 0.194062 0.833646 +vt 0.201239 0.830865 +vt 0.194470 0.744862 +vt 0.201590 0.746439 +vt 0.186935 0.745699 +vt 0.186576 0.834714 +vt 0.179572 0.744848 +vt 0.179033 0.837246 +vt 0.171637 0.746419 +vt 0.171519 0.837870 +vt 0.161340 0.747274 +vt 0.163011 0.841408 +vt 0.151935 0.747861 +vt 0.153283 0.841493 +vt 0.143363 0.748025 +vt 0.143363 0.840723 +vt 0.186530 0.846171 +vt 0.178971 0.848020 +vt 0.171503 0.850223 +vt 0.163195 0.851774 +vt 0.153417 0.850824 +vt 0.143363 0.849792 +vt 0.171849 0.900852 +vt 0.163275 0.873028 +vt 0.163162 0.908601 +vt 0.163275 0.873028 +vt 0.171849 0.900852 +vt 0.179072 0.898666 +vt 0.171849 0.900852 +vt 0.179072 0.898666 +vt 0.186546 0.898576 +vt 0.179072 0.898666 +vt 0.186546 0.898576 +vt 0.194021 0.897027 +vt 0.186546 0.898576 +vt 0.194021 0.897027 +vt 0.200740 0.902185 +vt 0.194021 0.897027 +vt 0.200898 0.881107 +vt 0.200740 0.902185 +vt 0.217429 0.747861 +vt 0.227026 0.840723 +vt 0.227026 0.748025 +vt 0.217539 0.836306 +vt 0.210524 0.747311 +vt 0.209201 0.832707 +vt 0.227026 0.849792 +vt 0.217553 0.847070 +vt 0.209024 0.844133 +vt 0.208737 0.856468 +vt 0.201181 0.855708 +vt 0.217549 0.857155 +vt 0.227026 0.857319 +vt 0.330899 0.433803 +vt 0.330899 0.449614 +vt 0.323620 0.449614 +vt 0.323620 0.449614 +vt 0.323620 0.433803 +vt 0.323620 0.449614 +vt 0.315590 0.449614 +vt 0.323620 0.449614 +vt 0.315590 0.433803 +vt 0.308829 0.449614 +vt 0.308829 0.433803 +vt 0.301540 0.449614 +vt 0.301540 0.433803 +vt 0.295151 0.449614 +vt 0.295151 0.433803 +vt 0.288067 0.449614 +vt 0.288067 0.433803 +vt 0.295151 0.433803 +vt 0.295151 0.417163 +vt 0.295151 0.433803 +vt 0.301540 0.417163 +vt 0.295151 0.433803 +vt 0.323620 0.433803 +vt 0.315590 0.449614 +vt 0.323620 0.433803 +vt 0.330899 0.417163 +vt 0.323620 0.433803 +vt 0.323620 0.417163 +vt 0.315590 0.417163 +vt 0.308829 0.417163 +vt 0.301540 0.417163 +vt 0.301540 0.417163 +vt 0.295151 0.417163 +vt 0.301540 0.417163 +vt 0.295151 0.417163 +vt 0.288067 0.417163 +vt 0.295151 0.417163 +vt 0.239121 0.448260 +vt 0.238299 0.422809 +vt 0.253440 0.422809 +vt 0.220085 0.422810 +vt 0.220085 0.450906 +vt 0.239121 0.448260 +vt 0.239121 0.459909 +vt 0.239121 0.448260 +vt 0.250234 0.455676 +vt 0.239121 0.448260 +vt 0.190404 0.704317 +vt 0.190404 0.678124 +vt 0.169617 0.670912 +vt 0.205779 0.685776 +vt 0.205779 0.722461 +vt 0.210809 0.705833 +vt 0.219455 0.725883 +vt 0.250234 0.445647 +vt 0.253440 0.432001 +vt 0.250234 0.455676 +vt 0.239121 0.459909 +vt 0.250234 0.455676 +vt 0.092911 0.908808 +vt 0.086493 0.908808 +vt 0.092911 0.923992 +vt 0.086493 0.893181 +vt 0.092911 0.893180 +vt 0.092911 0.878515 +vt 0.086493 0.940540 +vt 0.092911 0.940540 +vt 0.092911 0.958040 +vt 0.086493 0.958041 +vt 0.086493 0.972121 +vt 0.092911 0.972121 +vt 0.092911 0.958040 +vt 0.086493 0.958041 +vt 0.092911 0.958040 +vt 0.086493 0.940540 +vt 0.092911 0.958040 +vt 0.086493 0.958041 +vt 0.086493 0.940540 +vt 0.092911 0.940540 +vt 0.092911 0.958040 +vt 0.092911 0.923992 +vt 0.092911 0.940540 +vt 0.086493 0.940540 +vt 0.086493 0.923992 +vt 0.092911 0.923992 +vt 0.086493 0.940540 +vt 0.086493 0.908808 +vt 0.092911 0.923992 +vt 0.086493 0.893181 +vt 0.092911 0.893180 +vt 0.092911 0.908808 +vt 0.092911 0.893180 +vt 0.086493 0.893181 +vt 0.086493 0.878515 +vt 0.086493 0.893181 +vt 0.295151 0.433803 +vt 0.295151 0.449614 +vt 0.301540 0.433803 +vt 0.295151 0.449614 +vt 0.295151 0.433803 +vt 0.301540 0.433803 +vt 0.295151 0.433803 +vt 0.308829 0.417163 +vt 0.301540 0.433803 +vt 0.301540 0.433803 +vt 0.301540 0.449614 +vt 0.295151 0.449614 +vt 0.308829 0.433803 +vt 0.301540 0.449614 +vt 0.301540 0.433803 +vt 0.308829 0.417163 +vt 0.308829 0.433803 +vt 0.301540 0.433803 +vt 0.315590 0.417163 +vt 0.308829 0.433803 +vt 0.308829 0.417163 +vt 0.308829 0.433803 +vt 0.308829 0.449614 +vt 0.301540 0.449614 +vt 0.315590 0.433803 +vt 0.308829 0.449614 +vt 0.308829 0.433803 +vt 0.315590 0.417163 +vt 0.315590 0.433803 +vt 0.308829 0.433803 +vt 0.323620 0.417163 +vt 0.315590 0.433803 +vt 0.315590 0.417163 +vt 0.315590 0.433803 +vt 0.315590 0.449614 +vt 0.308829 0.449614 +vt 0.323620 0.433803 +vt 0.315590 0.449614 +vt 0.315590 0.433803 +vt 0.323620 0.417163 +vt 0.323620 0.433803 +vt 0.315590 0.433803 +vt 0.323620 0.433803 +vt 0.323620 0.417163 +vt 0.205779 0.722461 +vt 0.219455 0.725883 +vt 0.214339 0.738780 +vt 0.210809 0.705833 +vt 0.219455 0.725883 +vt 0.205779 0.722461 +vt 0.205779 0.685776 +vt 0.210809 0.705833 +vt 0.205779 0.722461 +vt 0.190404 0.704317 +vt 0.205779 0.685776 +vt 0.205779 0.722461 +vt 0.190404 0.678124 +vt 0.205779 0.685776 +vt 0.190404 0.704317 +vt 0.190404 0.678124 +vt 0.190404 0.704317 +vt 0.253440 0.422809 +vt 0.261637 0.432001 +vt 0.261637 0.422809 +vt 0.253440 0.432001 +vt 0.253440 0.422809 +vt 0.250234 0.445647 +vt 0.253440 0.432001 +vt 0.253440 0.422809 +vt 0.169617 0.694314 +vt 0.190404 0.704317 +vt 0.261637 0.432001 +vt 0.261637 0.422809 +vt 0.261637 0.432001 +vt 0.239121 0.459909 +vt 0.220085 0.461954 +vt 0.239121 0.459909 +vt 0.250234 0.445647 +vt 0.239121 0.448260 +vt 0.253440 0.422809 +vt 0.239121 0.448260 +vt 0.250234 0.445647 +vt 0.238299 0.422809 +vt 0.239121 0.448260 +vt 0.253440 0.422809 +vt 0.239121 0.448260 +vt 0.238299 0.422809 +vt 0.086493 0.923992 +vt 0.086493 0.923992 +vt 0.086493 0.908808 +vt 0.092911 0.908808 +vt 0.092911 0.923992 +vt 0.086493 0.893181 +vt 0.092911 0.908808 +vt 0.086493 0.908808 +vt 0.214339 0.738780 +vt 0.200525 0.930736 +vt 0.193963 0.920208 +vt 0.193937 0.930962 +vt 0.193963 0.920208 +vt 0.200525 0.930736 +vt 0.200375 0.939944 +vt 0.193937 0.930962 +vt 0.200525 0.930736 +vt 0.193898 0.940786 +vt 0.193937 0.930962 +vt 0.200375 0.939944 +vt 0.179120 0.930972 +vt 0.186590 0.940223 +vt 0.179078 0.940843 +vt 0.186536 0.929962 +vt 0.186590 0.940223 +vt 0.179120 0.930972 +vt 0.179104 0.920435 +vt 0.186536 0.929962 +vt 0.179120 0.930972 +vt 0.186539 0.920029 +vt 0.186536 0.929962 +vt 0.179104 0.920435 +vt 0.186536 0.929962 +vt 0.193898 0.940786 +vt 0.186590 0.940223 +vt 0.193937 0.930962 +vt 0.193898 0.940786 +vt 0.186536 0.929962 +vt 0.186539 0.920029 +vt 0.193937 0.930962 +vt 0.186536 0.929962 +vt 0.193963 0.920208 +vt 0.193937 0.930962 +vt 0.186539 0.920029 +vt 0.179120 0.930972 +vt 0.172027 0.922441 +vt 0.179104 0.920435 +vt 0.172090 0.930750 +vt 0.172027 0.922441 +vt 0.179120 0.930972 +vt 0.172011 0.945279 +vt 0.171985 0.950515 +vt 0.172037 0.940043 +vt 0.172037 0.940043 +vt 0.172090 0.930750 +vt 0.172037 0.940043 +vt 0.172037 0.940043 +vt 0.179058 0.945779 +vt 0.179078 0.940843 +vt 0.172037 0.940043 +vt 0.172090 0.930750 +vt 0.179078 0.940843 +vt 0.172037 0.940043 +vt 0.179120 0.930972 +vt 0.179078 0.940843 +vt 0.172090 0.930750 +vt 0.200299 0.944547 +vt 0.193898 0.940786 +vt 0.200375 0.939944 +vt 0.193879 0.945698 +vt 0.193898 0.940786 +vt 0.186590 0.940223 +vt 0.193898 0.940786 +vt 0.186618 0.945353 +vt 0.186590 0.940223 +vt 0.179078 0.940843 +vt 0.186590 0.940223 +vt 0.179078 0.940843 +vt 0.175598 0.977697 +vt 0.171985 0.950515 +vt 0.170005 0.978102 +vt 0.179037 0.950715 +vt 0.171985 0.950515 +vt 0.183547 0.982359 +vt 0.186645 0.950484 +vt 0.189970 0.986595 +vt 0.193860 0.950609 +vt 0.196637 0.991176 +vt 0.200224 0.949151 +vt 0.203572 0.994848 +vt 0.190404 0.678124 +vt 0.205779 0.667592 +vt 0.205779 0.685776 +vt 0.190404 0.653483 +vt 0.190404 0.678124 +vt 0.190404 0.678124 +vt 0.169617 0.646872 +vt 0.190404 0.653483 +vt 0.190404 0.643867 +vt 0.190404 0.653483 +vt 0.205779 0.658892 +vt 0.190404 0.653483 +vt 0.205779 0.632017 +vt 0.205779 0.658892 +vt 0.190404 0.643867 +vt 0.205779 0.658892 +vt 0.190404 0.643867 +vt 0.169617 0.636775 +vt 0.190404 0.643867 +vt 0.190404 0.616391 +vt 0.205779 0.611680 +vt 0.196637 0.991176 +vt 0.200224 0.949151 +vt 0.203572 0.994848 +vt 0.193860 0.950609 +vt 0.200224 0.949151 +vt 0.196637 0.991176 +vt 0.189970 0.986595 +vt 0.193860 0.950609 +vt 0.196637 0.991176 +vt 0.186645 0.950484 +vt 0.193860 0.950609 +vt 0.189970 0.986595 +vt 0.183547 0.982359 +vt 0.186645 0.950484 +vt 0.189970 0.986595 +vt 0.179037 0.950715 +vt 0.186645 0.950484 +vt 0.183547 0.982359 +vt 0.175598 0.977697 +vt 0.179037 0.950715 +vt 0.183547 0.982359 +vt 0.190404 0.643867 +vt 0.205779 0.632017 +vt 0.205779 0.658892 +vt 0.190404 0.616391 +vt 0.205779 0.632017 +vt 0.190404 0.643867 +vt 0.190404 0.616391 +vt 0.190404 0.643867 +vt 0.169617 0.609780 +vt 0.190404 0.616391 +vt 0.238299 0.515802 +vt 0.239121 0.459909 +vt 0.250234 0.455676 +vt 0.239121 0.459909 +vt 0.220085 0.512797 +vt 0.238299 0.515802 +vt 0.190404 0.595815 +vt 0.169617 0.591121 +vt 0.190404 0.595815 +vt 0.190404 0.616391 +vt 0.205779 0.611680 +vt 0.205779 0.632017 +vt 0.190404 0.595815 +vt 0.205779 0.611680 +vt 0.190404 0.616391 +vt 0.190404 0.595815 +vt 0.190404 0.616391 +vt 0.190404 0.653483 +vt 0.205779 0.667592 +vt 0.205779 0.667592 +vt 0.190404 0.653483 +vt 0.190404 0.653483 +vt 0.175598 0.977697 +vt 0.170005 0.978102 +vt 0.179037 0.950715 +vt 0.175598 0.977697 +vt 0.238299 0.515802 +vt 0.238299 0.515802 +vt 0.205779 0.667592 +vt 0.201239 0.830865 +vt 0.194470 0.744862 +vt 0.201590 0.746439 +vt 0.194062 0.833646 +vt 0.194470 0.744862 +vt 0.201239 0.830865 +vt 0.201188 0.843044 +vt 0.194062 0.833646 +vt 0.201239 0.830865 +vt 0.194012 0.844397 +vt 0.194062 0.833646 +vt 0.201188 0.843044 +vt 0.194075 0.855219 +vt 0.194012 0.844397 +vt 0.201188 0.843044 +vt 0.186559 0.854939 +vt 0.194012 0.844397 +vt 0.194075 0.855219 +vt 0.186555 0.867048 +vt 0.186559 0.854939 +vt 0.194075 0.855219 +vt 0.179007 0.855211 +vt 0.186559 0.854939 +vt 0.186555 0.867048 +vt 0.179023 0.865367 +vt 0.179007 0.855211 +vt 0.186555 0.867048 +vt 0.171522 0.855699 +vt 0.179007 0.855211 +vt 0.179023 0.865367 +vt 0.171587 0.864228 +vt 0.171522 0.855699 +vt 0.179023 0.865367 +vt 0.163344 0.856449 +vt 0.171522 0.855699 +vt 0.171587 0.864228 +vt 0.163311 0.864364 +vt 0.163344 0.856449 +vt 0.171587 0.864228 +vt 0.153616 0.857133 +vt 0.163344 0.856449 +vt 0.163311 0.864364 +vt 0.153620 0.865420 +vt 0.153616 0.857133 +vt 0.163311 0.864364 +vt 0.143432 0.857319 +vt 0.153616 0.857133 +vt 0.153620 0.865420 +vt 0.143363 0.869357 +vt 0.143432 0.857319 +vt 0.153620 0.865420 +vt 0.227026 0.840723 +vt 0.217429 0.747861 +vt 0.227026 0.748025 +vt 0.217539 0.836306 +vt 0.217429 0.747861 +vt 0.227026 0.840723 +vt 0.227026 0.849792 +vt 0.217539 0.836306 +vt 0.227026 0.840723 +vt 0.217553 0.847070 +vt 0.217539 0.836306 +vt 0.227026 0.849792 +vt 0.217549 0.857155 +vt 0.217553 0.847070 +vt 0.227026 0.849792 +vt 0.209024 0.844133 +vt 0.217553 0.847070 +vt 0.217549 0.857155 +vt 0.208737 0.856468 +vt 0.209024 0.844133 +vt 0.217549 0.857155 +vt 0.201188 0.843044 +vt 0.209024 0.844133 +vt 0.208737 0.856468 +vt 0.201181 0.855708 +vt 0.201188 0.843044 +vt 0.208737 0.856468 +vt 0.194075 0.855219 +vt 0.201188 0.843044 +vt 0.201181 0.855708 +vt 0.200983 0.869752 +vt 0.194075 0.855219 +vt 0.201181 0.855708 +vt 0.194104 0.863247 +vt 0.194075 0.855219 +vt 0.200983 0.869752 +vt 0.194104 0.863247 +vt 0.200983 0.869752 +vt 0.194078 0.873847 +vt 0.194104 0.863247 +vt 0.194078 0.873847 +vt 0.194078 0.873847 +vt 0.179033 0.837246 +vt 0.171637 0.746419 +vt 0.179572 0.744848 +vt 0.171519 0.837870 +vt 0.171637 0.746419 +vt 0.179033 0.837246 +vt 0.178971 0.848020 +vt 0.171519 0.837870 +vt 0.179033 0.837246 +vt 0.171503 0.850223 +vt 0.171519 0.837870 +vt 0.178971 0.848020 +vt 0.171522 0.855699 +vt 0.171503 0.850223 +vt 0.178971 0.848020 +vt 0.163195 0.851774 +vt 0.171503 0.850223 +vt 0.171522 0.855699 +vt 0.163344 0.856449 +vt 0.163195 0.851774 +vt 0.171522 0.855699 +vt 0.153417 0.850824 +vt 0.163195 0.851774 +vt 0.163344 0.856449 +vt 0.153616 0.857133 +vt 0.153417 0.850824 +vt 0.163344 0.856449 +vt 0.143432 0.857319 +vt 0.153417 0.850824 +vt 0.153616 0.857133 +vt 0.194062 0.833646 +vt 0.186935 0.745699 +vt 0.194470 0.744862 +vt 0.186576 0.834714 +vt 0.186935 0.745699 +vt 0.194062 0.833646 +vt 0.194012 0.844397 +vt 0.186576 0.834714 +vt 0.194062 0.833646 +vt 0.186530 0.846171 +vt 0.186576 0.834714 +vt 0.194012 0.844397 +vt 0.186559 0.854939 +vt 0.186530 0.846171 +vt 0.194012 0.844397 +vt 0.179007 0.855211 +vt 0.186530 0.846171 +vt 0.186559 0.854939 +vt 0.186576 0.834714 +vt 0.179572 0.744848 +vt 0.186935 0.745699 +vt 0.179033 0.837246 +vt 0.179572 0.744848 +vt 0.186576 0.834714 +vt 0.186530 0.846171 +vt 0.179033 0.837246 +vt 0.186576 0.834714 +vt 0.178971 0.848020 +vt 0.179033 0.837246 +vt 0.186530 0.846171 +vt 0.179007 0.855211 +vt 0.178971 0.848020 +vt 0.186530 0.846171 +vt 0.171522 0.855699 +vt 0.178971 0.848020 +vt 0.179007 0.855211 +vt 0.153283 0.841493 +vt 0.143363 0.748025 +vt 0.151935 0.747861 +vt 0.143363 0.840723 +vt 0.143363 0.748025 +vt 0.153283 0.841493 +vt 0.153417 0.850824 +vt 0.143363 0.840723 +vt 0.153283 0.841493 +vt 0.143363 0.849792 +vt 0.143363 0.840723 +vt 0.153417 0.850824 +vt 0.143432 0.857319 +vt 0.143363 0.849792 +vt 0.153417 0.850824 +vt 0.186552 0.877123 +vt 0.194078 0.873847 +vt 0.186552 0.877123 +vt 0.186555 0.867048 +vt 0.194078 0.873847 +vt 0.186552 0.877123 +vt 0.194104 0.863247 +vt 0.194078 0.873847 +vt 0.186555 0.867048 +vt 0.194075 0.855219 +vt 0.194104 0.863247 +vt 0.186555 0.867048 +vt 0.217409 0.864958 +vt 0.227026 0.869357 +vt 0.217409 0.864958 +vt 0.217549 0.857155 +vt 0.227026 0.869357 +vt 0.217409 0.864958 +vt 0.227026 0.857319 +vt 0.227026 0.869357 +vt 0.217549 0.857155 +vt 0.227026 0.849792 +vt 0.227026 0.857319 +vt 0.217549 0.857155 +vt 0.217539 0.836306 +vt 0.210524 0.747311 +vt 0.217429 0.747861 +vt 0.209201 0.832707 +vt 0.210524 0.747311 +vt 0.217539 0.836306 +vt 0.217553 0.847070 +vt 0.209201 0.832707 +vt 0.217539 0.836306 +vt 0.209024 0.844133 +vt 0.209201 0.832707 +vt 0.217553 0.847070 +vt 0.209201 0.832707 +vt 0.201590 0.746439 +vt 0.210524 0.747311 +vt 0.201239 0.830865 +vt 0.201590 0.746439 +vt 0.209201 0.832707 +vt 0.209024 0.844133 +vt 0.201239 0.830865 +vt 0.209201 0.832707 +vt 0.201188 0.843044 +vt 0.201239 0.830865 +vt 0.209024 0.844133 +vt 0.171519 0.837870 +vt 0.161340 0.747274 +vt 0.171637 0.746419 +vt 0.163011 0.841408 +vt 0.161340 0.747274 +vt 0.171519 0.837870 +vt 0.171503 0.850223 +vt 0.163011 0.841408 +vt 0.171519 0.837870 +vt 0.163195 0.851774 +vt 0.163011 0.841408 +vt 0.171503 0.850223 +vt 0.163011 0.841408 +vt 0.151935 0.747861 +vt 0.161340 0.747274 +vt 0.153283 0.841493 +vt 0.151935 0.747861 +vt 0.163011 0.841408 +vt 0.163195 0.851774 +vt 0.153283 0.841493 +vt 0.163011 0.841408 +vt 0.153417 0.850824 +vt 0.153283 0.841493 +vt 0.163195 0.851774 +vt 0.171670 0.875272 +vt 0.163311 0.864364 +vt 0.171670 0.875272 +vt 0.171587 0.864228 +vt 0.171670 0.875272 +vt 0.163311 0.864364 +vt 0.171670 0.875272 +vt 0.179040 0.876896 +vt 0.171670 0.875272 +vt 0.171587 0.864228 +vt 0.179040 0.876896 +vt 0.171670 0.875272 +vt 0.179023 0.865367 +vt 0.179040 0.876896 +vt 0.171587 0.864228 +vt 0.179040 0.876896 +vt 0.186552 0.877123 +vt 0.179040 0.876896 +vt 0.179023 0.865367 +vt 0.186552 0.877123 +vt 0.179040 0.876896 +vt 0.186555 0.867048 +vt 0.186552 0.877123 +vt 0.179023 0.865367 +vt 0.200983 0.869752 +vt 0.208973 0.870845 +vt 0.200983 0.869752 +vt 0.201181 0.855708 +vt 0.208973 0.870845 +vt 0.200983 0.869752 +vt 0.208737 0.856468 +vt 0.208973 0.870845 +vt 0.201181 0.855708 +vt 0.208973 0.870845 +vt 0.217409 0.864958 +vt 0.208973 0.870845 +vt 0.208737 0.856468 +vt 0.217409 0.864958 +vt 0.208973 0.870845 +vt 0.217549 0.857155 +vt 0.217409 0.864958 +vt 0.208737 0.856468 +vt 0.220085 0.583205 +vt 0.238299 0.515802 +vt 0.143363 0.869357 +vt 0.153620 0.865420 +vt 0.143363 0.869357 +vt 0.153620 0.865420 +vt 0.163311 0.864364 +vt 0.153620 0.865420 +vt 0.190404 0.595815 +vt 0.205779 0.584878 +vt 0.205779 0.611680 +vt 0.190404 0.565068 +vt 0.190404 0.595815 +vt 0.190404 0.595815 +vt 0.169617 0.558457 +vt 0.190404 0.565068 +vt 0.169617 0.457531 +vt 0.190404 0.565068 +vt 0.190404 0.466074 +vt 0.190404 0.565068 +vt 0.162505 0.949154 +vt 0.162203 0.954468 +vt 0.170005 0.978102 +vt 0.157354 0.978102 +vt 0.170005 0.978102 +vt 0.190404 0.565068 +vt 0.203848 0.476969 +vt 0.205779 0.584878 +vt 0.190404 0.565068 +vt 0.205779 0.584878 +vt 0.190404 0.565068 +vt 0.205779 0.584878 +vt 0.190404 0.466074 +vt 0.203848 0.476969 +vt 0.190404 0.466074 +vt 0.203848 0.476969 +vt 0.190404 0.565068 +vt 0.143673 0.977604 +vt 0.141866 0.954468 +vt 0.141866 0.977604 +vt 0.143673 0.954468 +vt 0.150470 0.977604 +vt 0.150470 0.954468 +vt 0.157354 0.978102 +vt 0.162203 0.954468 +vt 0.157354 0.978102 +vt 0.218406 0.953961 +vt 0.227036 0.959665 +vt 0.227036 0.940405 +vt 0.218334 0.959853 +vt 0.214670 0.959748 +vt 0.215381 0.975815 +vt 0.143673 0.949154 +vt 0.149850 0.949154 +vt 0.141866 0.949154 +vt 0.220181 0.975664 +vt 0.227036 0.975747 +vt 0.153651 0.949154 +vt 0.162203 0.954468 +vt 0.162505 0.949154 +vt 0.162203 0.954468 +vt 0.145995 0.977604 +vt 0.209548 0.943681 +vt 0.216487 0.938920 +vt 0.227036 0.939101 +vt 0.153653 0.936535 +vt 0.162973 0.943792 +vt 0.163016 0.935852 +vt 0.153651 0.938873 +vt 0.162973 0.943792 +vt 0.153653 0.936535 +vt 0.143363 0.938873 +vt 0.153653 0.936535 +vt 0.209050 0.935880 +vt 0.216489 0.936560 +vt 0.209050 0.935880 +vt 0.227036 0.936751 +vt 0.216489 0.936560 +vt 0.143673 0.941083 +vt 0.141866 0.941083 +vt 0.162505 0.949154 +vt 0.162973 0.943792 +vt 0.162505 0.949154 +vt 0.143363 0.936535 +vt 0.153653 0.936535 +vt 0.227036 0.936751 +vt 0.209050 0.935880 +vt 0.200581 0.923264 +vt 0.200740 0.902185 +vt 0.200581 0.923264 +vt 0.209050 0.935880 +vt 0.209032 0.920106 +vt 0.200740 0.902185 +vt 0.209050 0.935880 +vt 0.200898 0.881107 +vt 0.200740 0.902185 +vt 0.209032 0.920106 +vt 0.208991 0.885973 +vt 0.200898 0.881107 +vt 0.209032 0.920106 +vt 0.216489 0.936560 +vt 0.209032 0.920106 +vt 0.209050 0.935880 +vt 0.208991 0.885973 +vt 0.209032 0.920106 +vt 0.216489 0.936560 +vt 0.217259 0.876626 +vt 0.208991 0.885973 +vt 0.216489 0.936560 +vt 0.209050 0.935880 +vt 0.194021 0.897027 +vt 0.200581 0.923264 +vt 0.200740 0.902185 +vt 0.200581 0.923264 +vt 0.194021 0.897027 +vt 0.186546 0.898576 +vt 0.194021 0.897027 +vt 0.186546 0.898576 +vt 0.179072 0.898666 +vt 0.186546 0.898576 +vt 0.179072 0.898666 +vt 0.171849 0.900852 +vt 0.179072 0.898666 +vt 0.171849 0.900852 +vt 0.163162 0.908601 +vt 0.171849 0.900852 +vt 0.163048 0.928211 +vt 0.163162 0.908601 +vt 0.153644 0.916930 +vt 0.163048 0.928211 +vt 0.163162 0.908601 +vt 0.153653 0.936535 +vt 0.163048 0.928211 +vt 0.153644 0.916930 +vt 0.143363 0.936535 +vt 0.153653 0.936535 +vt 0.153644 0.916930 +vt 0.153644 0.916930 +vt 0.143363 0.879940 +vt 0.143363 0.936535 +vt 0.153624 0.875007 +vt 0.143363 0.879940 +vt 0.153644 0.916930 +vt 0.163162 0.908601 +vt 0.153624 0.875007 +vt 0.153644 0.916930 +vt 0.163275 0.873028 +vt 0.153624 0.875007 +vt 0.163162 0.908601 +vt 0.163016 0.935852 +vt 0.163048 0.928211 +vt 0.153653 0.936535 +vt 0.163048 0.928211 +vt 0.163016 0.935852 +vt 0.200581 0.923264 +vt 0.217259 0.876626 +vt 0.227036 0.936751 +vt 0.227026 0.879940 +vt 0.216489 0.936560 +vt 0.227036 0.936751 +vt 0.217259 0.876626 +vt 0.163048 0.928211 +vt 0.143363 0.938873 +vt 0.153651 0.938873 +vt 0.143363 0.938873 +vt 0.153651 0.938873 +vt 0.153651 0.938873 +vt 0.143673 0.949154 +vt 0.143673 0.941083 +vt 0.149850 0.949154 +vt 0.141866 0.941083 +vt 0.143673 0.941083 +vt 0.143673 0.949154 +vt 0.141866 0.949154 +vt 0.141866 0.941083 +vt 0.143673 0.949154 +vt 0.216487 0.938920 +vt 0.216487 0.938920 +vt 0.227036 0.939101 +vt 0.216487 0.938920 +vt 0.227036 0.940405 +vt 0.216487 0.938920 +vt 0.227036 0.939101 +vt 0.218406 0.953961 +vt 0.216487 0.938920 +vt 0.227036 0.940405 +vt 0.153651 0.949154 +vt 0.153651 0.938873 +vt 0.141866 0.954468 +vt 0.143673 0.977604 +vt 0.141866 0.977604 +vt 0.143673 0.954468 +vt 0.143673 0.977604 +vt 0.141866 0.954468 +vt 0.141866 0.949154 +vt 0.143673 0.954468 +vt 0.141866 0.954468 +vt 0.143673 0.949154 +vt 0.143673 0.954468 +vt 0.141866 0.949154 +vt 0.227036 0.959665 +vt 0.218406 0.953961 +vt 0.227036 0.940405 +vt 0.218334 0.959853 +vt 0.218406 0.953961 +vt 0.227036 0.959665 +vt 0.227036 0.975747 +vt 0.218334 0.959853 +vt 0.227036 0.959665 +vt 0.220181 0.975664 +vt 0.218334 0.959853 +vt 0.227036 0.975747 +vt 0.150470 0.954468 +vt 0.143673 0.949154 +vt 0.149850 0.949154 +vt 0.143673 0.954468 +vt 0.143673 0.949154 +vt 0.150470 0.954468 +vt 0.150470 0.977604 +vt 0.143673 0.954468 +vt 0.150470 0.954468 +vt 0.145995 0.977604 +vt 0.143673 0.954468 +vt 0.150470 0.977604 +vt 0.150470 0.954468 +vt 0.150470 0.977604 +vt 0.150470 0.954468 +vt 0.153651 0.949154 +vt 0.150470 0.954468 +vt 0.153651 0.949154 +vt 0.218334 0.959853 +vt 0.214670 0.959748 +vt 0.218406 0.953961 +vt 0.215381 0.975815 +vt 0.214670 0.959748 +vt 0.218334 0.959853 +vt 0.220181 0.975664 +vt 0.215381 0.975815 +vt 0.218334 0.959853 +vt 0.145995 0.977604 +vt 0.143673 0.977604 +vt 0.143673 0.954468 +vt 0.207519 0.953652 +vt 0.211436 0.982679 +vt 0.207519 0.953652 +vt 0.211436 0.982679 +vt 0.203572 0.994848 +vt 0.214670 0.959748 +vt 0.211436 0.982679 +vt 0.207519 0.953652 +vt 0.214670 0.959748 +vt 0.215381 0.975815 +vt 0.211436 0.982679 +vt 0.200299 0.944547 +vt 0.200299 0.944547 +vt 0.200299 0.944547 +vt 0.193879 0.945698 +vt 0.200299 0.944547 +vt 0.193879 0.945698 +vt 0.186618 0.945353 +vt 0.193879 0.945698 +vt 0.186618 0.945353 +vt 0.179058 0.945779 +vt 0.186618 0.945353 +vt 0.179058 0.945779 +vt 0.172011 0.945279 +vt 0.179058 0.945779 +vt 0.162203 0.954468 +vt 0.171985 0.950515 +vt 0.162505 0.949154 +vt 0.171985 0.950515 +vt 0.162203 0.954468 +vt 0.157354 0.978102 +vt 0.162203 0.954468 +vt 0.200299 0.944547 +vt 0.193879 0.945698 +vt 0.200299 0.944547 +vt 0.193879 0.945698 +vt 0.186618 0.945353 +vt 0.193879 0.945698 +vt 0.186618 0.945353 +vt 0.179058 0.945779 +vt 0.186618 0.945353 +vt 0.179058 0.945779 +vt 0.172011 0.945279 +vt 0.179058 0.945779 +vt 0.172011 0.945279 +vt 0.171985 0.950515 +vt 0.162505 0.949154 +vt 0.171985 0.950515 +vt 0.172011 0.945279 +vt 0.172011 0.945279 +vt 0.162973 0.943792 +vt 0.162505 0.949154 +vt 0.162973 0.943792 +vt 0.172011 0.945279 +vt 0.163016 0.935852 +vt 0.162973 0.943792 +vt 0.163016 0.935852 +vt 0.200224 0.949151 +vt 0.207519 0.953652 +vt 0.203572 0.994848 +vt 0.207519 0.953652 +vt 0.200224 0.949151 +vt 0.200224 0.949151 +vt 0.209548 0.943681 +vt 0.207519 0.953652 +vt 0.200375 0.939944 +vt 0.209548 0.943681 +vt 0.179037 0.950715 +vt 0.179037 0.950715 +vt 0.186645 0.950484 +vt 0.179037 0.950715 +vt 0.186645 0.950484 +vt 0.193860 0.950609 +vt 0.186645 0.950484 +vt 0.193860 0.950609 +vt 0.200224 0.949151 +vt 0.193860 0.950609 +vt 0.209548 0.943681 +vt 0.214670 0.959748 +vt 0.207519 0.953652 +vt 0.218406 0.953961 +vt 0.214670 0.959748 +vt 0.209548 0.943681 +vt 0.216487 0.938920 +vt 0.218406 0.953961 +vt 0.209548 0.943681 +vt 0.209548 0.943681 +vt 0.216487 0.938920 +vt 0.200525 0.930736 +vt 0.209548 0.943681 +vt 0.200375 0.939944 +vt 0.200525 0.930736 +vt 0.209548 0.943681 +vt 0.315335 0.370701 +vt 0.309854 0.392718 +vt 0.321083 0.392718 +vt 0.309843 0.355889 +vt 0.315335 0.357743 +vt 0.309843 0.330748 +vt 0.315335 0.333274 +vt 0.309843 0.272168 +vt 0.315335 0.272168 +vt 0.315335 0.205842 +vt 0.313031 0.205842 +vt 0.315335 0.370701 +vt 0.309854 0.392718 +vt 0.321083 0.392718 +vt 0.309843 0.355889 +vt 0.309854 0.392718 +vt 0.315335 0.370701 +vt 0.315335 0.357743 +vt 0.309843 0.355889 +vt 0.315335 0.370701 +vt 0.309843 0.330748 +vt 0.309843 0.355889 +vt 0.315335 0.357743 +vt 0.315335 0.333274 +vt 0.309843 0.330748 +vt 0.315335 0.357743 +vt 0.309843 0.272168 +vt 0.309843 0.330748 +vt 0.315335 0.333274 +vt 0.315335 0.272168 +vt 0.309843 0.272168 +vt 0.315335 0.333274 +vt 0.315335 0.205842 +vt 0.309843 0.272168 +vt 0.315335 0.272168 +vt 0.313031 0.205842 +vt 0.315335 0.205842 +vt 0.315335 0.272168 +vt 0.266605 0.319548 +vt 0.260309 0.322901 +vt 0.266605 0.348280 +vt 0.260309 0.280402 +vt 0.266605 0.280402 +vt 0.260309 0.269246 +vt 0.266605 0.269246 +vt 0.260309 0.228149 +vt 0.267980 0.214975 +vt 0.260309 0.208336 +vt 0.283285 0.327944 +vt 0.275896 0.331871 +vt 0.283285 0.361917 +vt 0.275896 0.286898 +vt 0.283285 0.286898 +vt 0.275896 0.275758 +vt 0.283285 0.275758 +vt 0.275855 0.232448 +vt 0.284645 0.212164 +vt 0.275736 0.210912 +vt 0.269076 0.327861 +vt 0.269076 0.362842 +vt 0.269076 0.286898 +vt 0.269076 0.275758 +vt 0.252838 0.207011 +vt 0.253565 0.269246 +vt 0.253565 0.280402 +vt 0.309843 0.355889 +vt 0.309843 0.330748 +vt 0.309843 0.355889 +vt 0.300443 0.356185 +vt 0.309843 0.330748 +vt 0.309843 0.355889 +vt 0.300443 0.331309 +vt 0.309843 0.330748 +vt 0.309843 0.330748 +vt 0.309843 0.272168 +vt 0.309843 0.330748 +vt 0.309843 0.272168 +vt 0.309843 0.330748 +vt 0.300443 0.283009 +vt 0.309843 0.272168 +vt 0.309843 0.355889 +vt 0.315335 0.333274 +vt 0.315335 0.357743 +vt 0.309843 0.330748 +vt 0.315335 0.333274 +vt 0.309843 0.355889 +vt 0.300443 0.356185 +vt 0.309843 0.330748 +vt 0.309843 0.355889 +vt 0.300443 0.331309 +vt 0.309843 0.330748 +vt 0.300443 0.356185 +vt 0.309843 0.330748 +vt 0.315335 0.272168 +vt 0.315335 0.333274 +vt 0.309843 0.272168 +vt 0.315335 0.272168 +vt 0.309843 0.330748 +vt 0.300443 0.331309 +vt 0.309843 0.272168 +vt 0.309843 0.330748 +vt 0.300443 0.283009 +vt 0.309843 0.272168 +vt 0.300443 0.331309 +vt 0.315335 0.205842 +vt 0.315335 0.272168 +vt 0.321084 0.205842 +vt 0.309843 0.272168 +vt 0.315335 0.272168 +vt 0.315335 0.205842 +vt 0.313031 0.205842 +vt 0.309843 0.272168 +vt 0.315335 0.205842 +vt 0.300505 0.205220 +vt 0.309843 0.272168 +vt 0.313031 0.205842 +vt 0.300443 0.272168 +vt 0.309843 0.272168 +vt 0.293098 0.228026 +vt 0.291683 0.206035 +vt 0.309843 0.355889 +vt 0.309854 0.392718 +vt 0.300443 0.392718 +vt 0.309854 0.392718 +vt 0.309843 0.355889 +vt 0.309843 0.355889 +vt 0.309843 0.355889 +vt 0.309854 0.392718 +vt 0.300443 0.392718 +vt 0.315335 0.370701 +vt 0.309854 0.392718 +vt 0.309843 0.355889 +vt 0.315335 0.357743 +vt 0.315335 0.370701 +vt 0.309843 0.355889 +vt 0.313031 0.205842 +vt 0.300505 0.205220 +vt 0.313031 0.205842 +vt 0.300443 0.272168 +vt 0.300505 0.205220 +vt 0.313031 0.205842 +vt 0.300443 0.272168 +vt 0.309843 0.272168 +vt 0.309843 0.272168 +vt 0.300443 0.272168 +vt 0.300505 0.205220 +vt 0.300443 0.272168 +vt 0.309843 0.272168 +vt 0.300443 0.272168 +vt 0.300443 0.283009 +vt 0.300505 0.205220 +vt 0.300443 0.272168 +vt 0.309843 0.272168 +vt 0.313031 0.205842 +vt 0.300505 0.205220 +vt 0.309843 0.272168 +vt 0.331166 0.272168 +vt 0.331166 0.205842 +vt 0.321084 0.272168 +vt 0.315335 0.272168 +vt 0.293098 0.272168 +vt 0.285634 0.272168 +vt 0.253565 0.349339 +vt 0.256602 0.359306 +vt 0.253565 0.318241 +vt 0.280069 0.373285 +vt 0.272112 0.373285 +vt 0.300443 0.331309 +vt 0.300443 0.356185 +vt 0.300443 0.331309 +vt 0.309843 0.355889 +vt 0.300443 0.331309 +vt 0.300443 0.356185 +vt 0.309843 0.330748 +vt 0.300443 0.331309 +vt 0.309843 0.355889 +vt 0.300443 0.272168 +vt 0.309843 0.272168 +vt 0.300443 0.283009 +vt 0.313031 0.205842 +vt 0.309843 0.272168 +vt 0.300443 0.272168 +vt 0.309843 0.330748 +vt 0.300443 0.283009 +vt 0.300443 0.331309 +vt 0.309843 0.272168 +vt 0.300443 0.283009 +vt 0.309843 0.330748 +vt 0.300443 0.283009 +vt 0.300443 0.331309 +vt 0.300443 0.283009 +vt 0.300443 0.272168 +vt 0.300443 0.283009 +vt 0.300505 0.205220 +vt 0.300443 0.272168 +vt 0.263957 0.359306 +vt 0.300443 0.392718 +vt 0.309854 0.392718 +vt 0.309843 0.355889 +vt 0.300443 0.392718 +vt 0.309843 0.272168 +vt 0.315335 0.205842 +vt 0.313031 0.205842 +vt 0.309843 0.272168 +vt 0.315335 0.272168 +vt 0.309843 0.272168 +vt 0.313031 0.205842 +vt 0.105372 0.209051 +vt 0.111422 0.161458 +vt 0.105424 0.161371 +vt 0.117761 0.200858 +vt 0.117872 0.239541 +vt 0.127910 0.245340 +vt 0.127910 0.278181 +vt 0.137341 0.266706 +vt 0.144765 0.278181 +vt 0.148833 0.262657 +vt 0.153313 0.262657 +vt 0.150715 0.239541 +vt 0.155154 0.239541 +vt 0.150045 0.209051 +vt 0.154167 0.209051 +vt 0.154163 0.169960 +vt 0.144900 0.097997 +vt 0.145924 0.158213 +vt 0.153536 0.111672 +vt 0.137241 0.145857 +vt 0.127839 0.093652 +vt 0.127910 0.140944 +vt 0.117647 0.098693 +vt 0.121934 0.145411 +vt 0.102327 0.209051 +vt 0.105424 0.183930 +vt 0.098683 0.169960 +vt 0.104336 0.239541 +vt 0.117872 0.265913 +vt 0.111729 0.278181 +vt 0.137241 0.200405 +vt 0.137341 0.239541 +vt 0.318364 0.180135 +vt 0.313031 0.205842 +vt 0.305174 0.173258 +vt 0.315441 0.173123 +vt 0.318364 0.092530 +vt 0.150013 0.165822 +vt 0.162115 0.127119 +vt 0.101340 0.239541 +vt 0.106106 0.262657 +vt 0.103181 0.262657 +vt 0.127910 0.204959 +vt 0.295828 0.168838 +vt 0.305174 0.092478 +vt 0.154167 0.209051 +vt 0.150013 0.165822 +vt 0.150045 0.209051 +vt 0.150013 0.165822 +vt 0.154167 0.209051 +vt 0.325105 0.165943 +vt 0.325105 0.162437 +vt 0.328644 0.163585 +vt 0.322585 0.160635 +vt 0.321622 0.162900 +vt 0.321622 0.155071 +vt 0.320100 0.155071 +vt 0.322802 0.150035 +vt 0.321622 0.146746 +vt 0.325105 0.148683 +vt 0.325105 0.144389 +vt 0.327626 0.150294 +vt 0.328644 0.146746 +vt 0.328590 0.155071 +vt 0.330110 0.155071 +vt 0.327626 0.160635 +vt 0.325105 0.165943 +vt 0.325105 0.162437 +vt 0.328644 0.163585 +vt 0.322585 0.160635 +vt 0.325105 0.162437 +vt 0.325105 0.165943 +vt 0.321622 0.162900 +vt 0.322585 0.160635 +vt 0.325105 0.165943 +vt 0.321622 0.155071 +vt 0.322585 0.160635 +vt 0.321622 0.162900 +vt 0.320100 0.155071 +vt 0.321622 0.155071 +vt 0.321622 0.162900 +vt 0.322802 0.150035 +vt 0.321622 0.155071 +vt 0.320100 0.155071 +vt 0.321622 0.146746 +vt 0.322802 0.150035 +vt 0.320100 0.155071 +vt 0.325105 0.148683 +vt 0.322802 0.150035 +vt 0.321622 0.146746 +vt 0.325105 0.144389 +vt 0.325105 0.148683 +vt 0.321622 0.146746 +vt 0.327626 0.150294 +vt 0.325105 0.148683 +vt 0.325105 0.144389 +vt 0.328644 0.146746 +vt 0.327626 0.150294 +vt 0.325105 0.144389 +vt 0.328590 0.155071 +vt 0.327626 0.150294 +vt 0.328644 0.146746 +vt 0.330110 0.155071 +vt 0.328590 0.155071 +vt 0.328644 0.146746 +vt 0.327626 0.160635 +vt 0.328590 0.155071 +vt 0.330110 0.155071 +vt 0.328644 0.163585 +vt 0.327626 0.160635 +vt 0.330110 0.155071 +vt 0.325105 0.162437 +vt 0.327626 0.160635 +vt 0.328644 0.163585 +vt 0.326366 0.112944 +vt 0.326298 0.108797 +vt 0.329919 0.110144 +vt 0.323963 0.107162 +vt 0.322813 0.110144 +vt 0.322996 0.103214 +vt 0.321341 0.103384 +vt 0.323963 0.099267 +vt 0.322813 0.096624 +vt 0.326298 0.097632 +vt 0.326366 0.093824 +vt 0.328634 0.099267 +vt 0.329919 0.096624 +vt 0.329601 0.103214 +vt 0.331391 0.103384 +vt 0.328634 0.107162 +vt 0.227442 0.198295 +vt 0.202203 0.164222 +vt 0.196936 0.203490 +vt 0.224053 0.164170 +vt 0.237497 0.195760 +vt 0.237556 0.165400 +vt 0.241414 0.166630 +vt 0.237506 0.092795 +vt 0.248304 0.095228 +vt 0.237085 0.054062 +vt 0.255343 0.054107 +vt 0.237085 0.036913 +vt 0.255343 0.038385 +vt 0.237085 0.022626 +vt 0.255343 0.022686 +vt 0.237085 0.006518 +vt 0.255343 0.006570 +vt 0.182199 0.212576 +vt 0.190329 0.229401 +vt 0.186427 0.164558 +vt 0.202254 0.100692 +vt 0.223928 0.090362 +vt 0.211880 0.054074 +vt 0.223987 0.054046 +vt 0.211880 0.038342 +vt 0.223987 0.038315 +vt 0.211880 0.022643 +vt 0.223986 0.022616 +vt 0.211880 0.006532 +vt 0.223987 0.006509 +vt 0.167478 0.215172 +vt 0.175952 0.232554 +vt 0.169600 0.140939 +vt 0.186420 0.100694 +vt 0.195219 0.054132 +vt 0.195219 0.038404 +vt 0.195219 0.022704 +vt 0.195219 0.006584 +vt 0.122433 0.072827 +vt 0.133617 0.056060 +vt 0.162403 0.056001 +vt 0.172467 0.054199 +vt 0.260205 0.170870 +vt 0.246034 0.168263 +vt 0.244660 0.198728 +vt 0.244660 0.216971 +vt 0.244660 0.256028 +vt 0.251622 0.256028 +vt 0.251622 0.266660 +vt 0.221458 0.256750 +vt 0.221458 0.202322 +vt 0.227442 0.256750 +vt 0.227442 0.303375 +vt 0.237497 0.302945 +vt 0.237497 0.330059 +vt 0.244660 0.308322 +vt 0.241246 0.341147 +vt 0.248396 0.341147 +vt 0.172467 0.022786 +vt 0.172467 0.038488 +vt 0.150932 0.022898 +vt 0.150932 0.038600 +vt 0.139726 0.022962 +vt 0.139726 0.038664 +vt 0.130539 0.022980 +vt 0.130539 0.038681 +vt 0.172467 0.006666 +vt 0.150932 0.006751 +vt 0.139726 0.006806 +vt 0.130539 0.006822 +vt 0.306886 0.006800 +vt 0.318364 0.022980 +vt 0.318364 0.006822 +vt 0.306886 0.022954 +vt 0.287698 0.006739 +vt 0.287698 0.022883 +vt 0.269172 0.006653 +vt 0.269172 0.022783 +vt 0.150932 0.054270 +vt 0.139726 0.054331 +vt 0.130539 0.054350 +vt 0.318364 0.037295 +vt 0.306886 0.037243 +vt 0.287698 0.038584 +vt 0.269172 0.038482 +vt 0.318364 0.054003 +vt 0.306886 0.054320 +vt 0.287698 0.054265 +vt 0.269172 0.054183 +vt 0.227442 0.330059 +vt 0.227442 0.363326 +vt 0.237497 0.363326 +vt 0.221457 0.345892 +vt 0.221458 0.330059 +vt 0.215533 0.330059 +vt 0.215533 0.303375 +vt 0.206100 0.303375 +vt 0.206100 0.266660 +vt 0.288985 0.099711 +vt 0.269172 0.098910 +vt 0.221458 0.303375 +vt 0.215533 0.256750 +vt 0.221458 0.202334 +vt 0.215533 0.206439 +vt 0.237497 0.256028 +vt 0.244660 0.266660 +vt 0.251622 0.305580 +vt 0.290619 0.168724 +vt 0.275533 0.170960 +vt 0.237497 0.266660 +vt 0.325105 0.155071 +vt 0.154167 0.209051 +vt 0.154167 0.209051 +vt 0.160076 0.231531 +vt 0.154167 0.209051 +vt 0.323171 0.068363 +vt 0.332692 0.053959 +vt 0.191706 0.294687 +vt 0.166466 0.426555 +vt 0.146111 0.368739 +vt 0.191706 0.445655 +vt 0.166466 0.426555 +vt 0.146111 0.368739 +vt 0.166466 0.426555 +vt 0.140464 0.294688 +vt 0.146111 0.368739 +vt 0.146111 0.368739 +vt 0.166466 0.426555 +vt 0.146111 0.368739 +vt 0.191706 0.445655 +vt 0.166466 0.426555 +vt 0.166466 0.426555 +vt 0.191706 0.445655 +vt 0.326366 0.103142 +vt 0.325105 0.155071 +vt 0.322802 0.150035 +vt 0.325105 0.148683 +vt 0.321622 0.155071 +vt 0.322802 0.150035 +vt 0.325105 0.155071 +vt 0.322585 0.160635 +vt 0.321622 0.155071 +vt 0.325105 0.155071 +vt 0.325105 0.155071 +vt 0.325105 0.162437 +vt 0.322585 0.160635 +vt 0.327626 0.160635 +vt 0.325105 0.162437 +vt 0.325105 0.155071 +vt 0.328590 0.155071 +vt 0.327626 0.160635 +vt 0.325105 0.155071 +vt 0.215533 0.363326 +vt 0.206100 0.256750 +vt 0.327626 0.150294 +vt 0.325105 0.155071 +vt 0.325105 0.148683 +vt 0.328590 0.155071 +vt 0.325105 0.155071 +vt 0.327626 0.150294 +vt 0.251622 0.332716 +vt 0.140464 0.294688 +vt 0.146111 0.368739 +vt 0.140464 0.294688 +vt 0.206100 0.204278 +vt 0.206100 0.363326 +vt 0.206100 0.330059 +vt 0.146111 0.368739 +vt 0.166466 0.426555 +vt 0.269172 0.022783 +vt 0.255343 0.006570 +vt 0.269172 0.006653 +vt 0.255343 0.022686 +vt 0.255343 0.006570 +vt 0.269172 0.022783 +vt 0.269172 0.038482 +vt 0.255343 0.022686 +vt 0.269172 0.022783 +vt 0.255343 0.038385 +vt 0.255343 0.022686 +vt 0.269172 0.038482 +vt 0.269172 0.054183 +vt 0.255343 0.038385 +vt 0.269172 0.038482 +vt 0.255343 0.054107 +vt 0.255343 0.038385 +vt 0.269172 0.054183 +vt 0.248304 0.095228 +vt 0.255343 0.054107 +vt 0.269172 0.054183 +vt 0.237085 0.054062 +vt 0.255343 0.054107 +vt 0.248304 0.095228 +vt 0.237506 0.092795 +vt 0.237085 0.054062 +vt 0.248304 0.095228 +vt 0.223987 0.054046 +vt 0.237085 0.054062 +vt 0.237506 0.092795 +vt 0.223928 0.090362 +vt 0.223987 0.054046 +vt 0.237506 0.092795 +vt 0.211880 0.054074 +vt 0.223987 0.054046 +vt 0.223928 0.090362 +vt 0.202254 0.100692 +vt 0.211880 0.054074 +vt 0.223928 0.090362 +vt 0.195219 0.054132 +vt 0.211880 0.054074 +vt 0.202254 0.100692 +vt 0.186420 0.100694 +vt 0.195219 0.054132 +vt 0.202254 0.100692 +vt 0.172467 0.054199 +vt 0.195219 0.054132 +vt 0.186420 0.100694 +vt 0.318364 0.022980 +vt 0.306886 0.006800 +vt 0.318364 0.006822 +vt 0.306886 0.022954 +vt 0.306886 0.006800 +vt 0.318364 0.022980 +vt 0.318364 0.037295 +vt 0.306886 0.022954 +vt 0.318364 0.022980 +vt 0.306886 0.037243 +vt 0.306886 0.022954 +vt 0.318364 0.037295 +vt 0.318364 0.054003 +vt 0.306886 0.037243 +vt 0.318364 0.037295 +vt 0.306886 0.054320 +vt 0.306886 0.037243 +vt 0.318364 0.054003 +vt 0.305174 0.092478 +vt 0.306886 0.054320 +vt 0.318364 0.054003 +vt 0.288985 0.099711 +vt 0.306886 0.054320 +vt 0.305174 0.092478 +vt 0.306886 0.022954 +vt 0.287698 0.006739 +vt 0.306886 0.006800 +vt 0.287698 0.022883 +vt 0.287698 0.006739 +vt 0.306886 0.022954 +vt 0.306886 0.037243 +vt 0.287698 0.022883 +vt 0.306886 0.022954 +vt 0.287698 0.038584 +vt 0.287698 0.022883 +vt 0.306886 0.037243 +vt 0.306886 0.054320 +vt 0.287698 0.038584 +vt 0.306886 0.037243 +vt 0.287698 0.054265 +vt 0.287698 0.038584 +vt 0.306886 0.054320 +vt 0.288985 0.099711 +vt 0.287698 0.054265 +vt 0.306886 0.054320 +vt 0.269172 0.098910 +vt 0.287698 0.054265 +vt 0.288985 0.099711 +vt 0.287698 0.022883 +vt 0.269172 0.006653 +vt 0.287698 0.006739 +vt 0.269172 0.022783 +vt 0.269172 0.006653 +vt 0.287698 0.022883 +vt 0.287698 0.038584 +vt 0.269172 0.022783 +vt 0.287698 0.022883 +vt 0.269172 0.038482 +vt 0.269172 0.022783 +vt 0.287698 0.038584 +vt 0.287698 0.054265 +vt 0.269172 0.038482 +vt 0.287698 0.038584 +vt 0.269172 0.054183 +vt 0.269172 0.038482 +vt 0.287698 0.054265 +vt 0.269172 0.098910 +vt 0.269172 0.054183 +vt 0.287698 0.054265 +vt 0.248304 0.095228 +vt 0.269172 0.054183 +vt 0.269172 0.098910 +vt 0.315335 0.357743 +vt 0.315335 0.370701 +vt 0.309843 0.355889 +vt 0.309843 0.355889 +vt 0.315335 0.370701 +vt 0.315335 0.357743 +vt 0.315335 0.333274 +vt 0.309843 0.355889 +vt 0.315335 0.357743 +vt 0.309843 0.330748 +vt 0.309843 0.355889 +vt 0.315335 0.333274 +vt 0.315335 0.272168 +vt 0.309843 0.330748 +vt 0.315335 0.333274 +vt 0.309843 0.272168 +vt 0.309843 0.330748 +vt 0.315335 0.272168 +vt 0.313031 0.205842 +vt 0.309843 0.272168 +vt 0.315335 0.272168 +vt 0.150932 0.022898 +vt 0.139726 0.006806 +vt 0.150932 0.006751 +vt 0.139726 0.022962 +vt 0.139726 0.006806 +vt 0.150932 0.022898 +vt 0.150932 0.038600 +vt 0.139726 0.022962 +vt 0.150932 0.022898 +vt 0.139726 0.038664 +vt 0.139726 0.022962 +vt 0.150932 0.038600 +vt 0.150932 0.054270 +vt 0.139726 0.038664 +vt 0.150932 0.038600 +vt 0.139726 0.054331 +vt 0.139726 0.038664 +vt 0.150932 0.054270 +vt 0.223986 0.022616 +vt 0.211880 0.006532 +vt 0.223987 0.006509 +vt 0.211880 0.022643 +vt 0.211880 0.006532 +vt 0.223986 0.022616 +vt 0.223987 0.038315 +vt 0.211880 0.022643 +vt 0.223986 0.022616 +vt 0.211880 0.038342 +vt 0.211880 0.022643 +vt 0.223987 0.038315 +vt 0.223987 0.054046 +vt 0.211880 0.038342 +vt 0.223987 0.038315 +vt 0.211880 0.054074 +vt 0.211880 0.038342 +vt 0.223987 0.054046 +vt 0.211880 0.022643 +vt 0.195219 0.006584 +vt 0.211880 0.006532 +vt 0.195219 0.022704 +vt 0.195219 0.006584 +vt 0.211880 0.022643 +vt 0.211880 0.038342 +vt 0.195219 0.022704 +vt 0.211880 0.022643 +vt 0.195219 0.038404 +vt 0.195219 0.022704 +vt 0.211880 0.038342 +vt 0.211880 0.054074 +vt 0.195219 0.038404 +vt 0.211880 0.038342 +vt 0.195219 0.054132 +vt 0.195219 0.038404 +vt 0.211880 0.054074 +vt 0.195219 0.022704 +vt 0.172467 0.006666 +vt 0.195219 0.006584 +vt 0.172467 0.022786 +vt 0.172467 0.006666 +vt 0.195219 0.022704 +vt 0.195219 0.038404 +vt 0.172467 0.022786 +vt 0.195219 0.022704 +vt 0.172467 0.038488 +vt 0.172467 0.022786 +vt 0.195219 0.038404 +vt 0.195219 0.054132 +vt 0.172467 0.038488 +vt 0.195219 0.038404 +vt 0.172467 0.054199 +vt 0.172467 0.038488 +vt 0.195219 0.054132 +vt 0.172467 0.022786 +vt 0.150932 0.006751 +vt 0.172467 0.006666 +vt 0.150932 0.022898 +vt 0.150932 0.006751 +vt 0.172467 0.022786 +vt 0.172467 0.038488 +vt 0.150932 0.022898 +vt 0.172467 0.022786 +vt 0.150932 0.038600 +vt 0.150932 0.022898 +vt 0.172467 0.038488 +vt 0.172467 0.054199 +vt 0.150932 0.038600 +vt 0.172467 0.038488 +vt 0.150932 0.054270 +vt 0.150932 0.038600 +vt 0.172467 0.054199 +vt 0.130539 0.038681 +vt 0.139726 0.054331 +vt 0.130539 0.054350 +vt 0.139726 0.038664 +vt 0.139726 0.054331 +vt 0.130539 0.038681 +vt 0.130539 0.022980 +vt 0.139726 0.038664 +vt 0.130539 0.038681 +vt 0.139726 0.022962 +vt 0.139726 0.038664 +vt 0.130539 0.022980 +vt 0.130539 0.006822 +vt 0.139726 0.022962 +vt 0.130539 0.022980 +vt 0.139726 0.006806 +vt 0.139726 0.022962 +vt 0.130539 0.006822 +vt 0.255343 0.022686 +vt 0.237085 0.006518 +vt 0.255343 0.006570 +vt 0.237085 0.022626 +vt 0.237085 0.006518 +vt 0.255343 0.022686 +vt 0.255343 0.038385 +vt 0.237085 0.022626 +vt 0.255343 0.022686 +vt 0.237085 0.036913 +vt 0.237085 0.022626 +vt 0.255343 0.038385 +vt 0.255343 0.054107 +vt 0.237085 0.036913 +vt 0.255343 0.038385 +vt 0.237085 0.054062 +vt 0.237085 0.036913 +vt 0.255343 0.054107 +vt 0.237085 0.022626 +vt 0.223987 0.006509 +vt 0.237085 0.006518 +vt 0.223986 0.022616 +vt 0.223987 0.006509 +vt 0.237085 0.022626 +vt 0.237085 0.036913 +vt 0.223986 0.022616 +vt 0.237085 0.022626 +vt 0.223987 0.038315 +vt 0.223986 0.022616 +vt 0.237085 0.036913 +vt 0.237085 0.054062 +vt 0.223987 0.038315 +vt 0.237085 0.036913 +vt 0.223987 0.054046 +vt 0.223987 0.038315 +vt 0.237085 0.054062 +vt 0.300443 0.331309 +vt 0.309843 0.355889 +vt 0.300443 0.356185 +vt 0.309843 0.330748 +vt 0.309843 0.355889 +vt 0.300443 0.331309 +vt 0.300443 0.283009 +vt 0.309843 0.330748 +vt 0.300443 0.331309 +vt 0.309843 0.272168 +vt 0.309843 0.330748 +vt 0.300443 0.283009 +vt 0.300443 0.272168 +vt 0.309843 0.272168 +vt 0.300443 0.283009 +vt 0.300505 0.205220 +vt 0.309843 0.272168 +vt 0.300443 0.272168 +vt 0.309843 0.330748 +vt 0.315335 0.357743 +vt 0.309843 0.355889 +vt 0.315335 0.333274 +vt 0.315335 0.357743 +vt 0.309843 0.330748 +vt 0.309843 0.272168 +vt 0.315335 0.333274 +vt 0.309843 0.330748 +vt 0.315335 0.272168 +vt 0.315335 0.333274 +vt 0.309843 0.272168 +vt 0.315335 0.205842 +vt 0.315335 0.272168 +vt 0.309843 0.272168 +vt 0.313031 0.205842 +vt 0.315335 0.272168 +vt 0.315335 0.205842 +vt 0.300443 0.272168 +vt 0.313031 0.205842 +vt 0.300505 0.205220 +vt 0.309843 0.272168 +vt 0.313031 0.205842 +vt 0.300443 0.272168 +vt 0.300443 0.283009 +vt 0.309843 0.272168 +vt 0.300443 0.272168 +vt 0.300443 0.331309 +vt 0.309843 0.272168 +vt 0.300443 0.283009 +vt 0.260309 0.322901 +vt 0.267910 0.319548 +vt 0.267910 0.348280 +vt 0.260309 0.280402 +vt 0.260309 0.322901 +vt 0.252874 0.280402 +vt 0.260309 0.280402 +vt 0.260309 0.322901 +vt 0.252874 0.269246 +vt 0.260309 0.280402 +vt 0.260309 0.280402 +vt 0.267910 0.280402 +vt 0.260309 0.269246 +vt 0.260309 0.280402 +vt 0.260309 0.269246 +vt 0.260309 0.280402 +vt 0.252838 0.207011 +vt 0.260309 0.269246 +vt 0.260309 0.269246 +vt 0.267910 0.269246 +vt 0.260309 0.228149 +vt 0.260309 0.269246 +vt 0.252838 0.207011 +vt 0.260309 0.228149 +vt 0.260309 0.269246 +vt 0.260309 0.208336 +vt 0.260309 0.228149 +vt 0.252838 0.207011 +vt 0.172467 0.054199 +vt 0.162115 0.127119 +vt 0.153536 0.111672 +vt 0.169600 0.140939 +vt 0.162115 0.127119 +vt 0.172467 0.054199 +vt 0.186420 0.100694 +vt 0.169600 0.140939 +vt 0.172467 0.054199 +vt 0.309854 0.392718 +vt 0.315335 0.370701 +vt 0.321083 0.392718 +vt 0.309843 0.355889 +vt 0.315335 0.370701 +vt 0.309854 0.392718 +vt 0.300443 0.392718 +vt 0.309843 0.355889 +vt 0.309854 0.392718 +vt 0.191706 0.294687 +vt 0.146111 0.368739 +vt 0.166466 0.426555 +vt 0.140464 0.294688 +vt 0.146111 0.368739 +vt 0.191706 0.294687 +vt 0.146111 0.368739 +vt 0.140464 0.294688 +vt 0.191706 0.294687 +vt 0.191706 0.294687 +vt 0.166466 0.426555 +vt 0.146111 0.368739 +vt 0.191706 0.445655 +vt 0.166466 0.426555 +vt 0.191706 0.294687 +vt 0.166466 0.426555 +vt 0.191706 0.445655 +vt 0.191706 0.294687 +vt 0.191706 0.294687 +vt 0.146111 0.368739 +vt 0.166466 0.426555 +vt 0.140464 0.294688 +vt 0.146111 0.368739 +vt 0.191706 0.294687 +vt 0.146111 0.368739 +vt 0.140464 0.294688 +vt 0.191706 0.294687 +vt 0.191706 0.294687 +vt 0.166466 0.426555 +vt 0.146111 0.368739 +vt 0.191706 0.445655 +vt 0.166466 0.426555 +vt 0.191706 0.294687 +vt 0.166466 0.426555 +vt 0.191706 0.445655 +vt 0.191706 0.294687 +vt 0.260309 0.322901 +vt 0.256602 0.359306 +vt 0.252874 0.349339 +vt 0.263957 0.359306 +vt 0.256602 0.359306 +vt 0.260309 0.322901 +vt 0.263957 0.359306 +vt 0.260309 0.322901 +vt 0.309843 0.330748 +vt 0.300443 0.356185 +vt 0.309843 0.355889 +vt 0.300443 0.331309 +vt 0.300443 0.356185 +vt 0.309843 0.330748 +vt 0.309843 0.272168 +vt 0.300443 0.331309 +vt 0.309843 0.330748 +vt 0.252874 0.318241 +vt 0.260309 0.322901 +vt 0.260309 0.322901 +vt 0.313031 0.205842 +vt 0.309843 0.272168 +vt 0.300505 0.205220 +vt 0.315335 0.205842 +vt 0.309843 0.272168 +vt 0.313031 0.205842 +vt 0.162403 0.056001 +vt 0.153536 0.111672 +vt 0.144900 0.097997 +vt 0.172467 0.054199 +vt 0.153536 0.111672 +vt 0.162403 0.056001 +vt 0.309854 0.392718 +vt 0.309843 0.355889 +vt 0.300443 0.392718 +vt 0.315335 0.370701 +vt 0.309843 0.355889 +vt 0.309854 0.392718 +vt 0.267980 0.214975 +vt 0.260309 0.228149 +vt 0.260309 0.208336 +vt 0.260309 0.228149 +vt 0.267980 0.214975 +vt 0.323171 0.068363 +vt 0.318364 0.054003 +vt 0.332692 0.053959 +vt 0.318364 0.092530 +vt 0.318364 0.054003 +vt 0.323171 0.068363 +vt 0.122433 0.072827 +vt 0.127839 0.093652 +vt 0.117647 0.098693 +vt 0.133617 0.056060 +vt 0.127839 0.093652 +vt 0.122433 0.072827 +vt 0.133617 0.056060 +vt 0.144900 0.097997 +vt 0.127839 0.093652 +vt 0.162403 0.056001 +vt 0.144900 0.097997 +vt 0.133617 0.056060 +vt 0.318364 0.092530 +vt 0.305174 0.092478 +vt 0.318364 0.054003 +vt 0.111422 0.161458 +vt 0.105372 0.209051 +vt 0.105424 0.161371 +vt 0.117761 0.200858 +vt 0.105372 0.209051 +vt 0.111422 0.161458 +vt 0.121934 0.145411 +vt 0.117761 0.200858 +vt 0.111422 0.161458 +vt 0.127910 0.204959 +vt 0.117761 0.200858 +vt 0.121934 0.145411 +vt 0.127910 0.140944 +vt 0.127910 0.204959 +vt 0.121934 0.145411 +vt 0.137241 0.200405 +vt 0.127910 0.204959 +vt 0.127910 0.140944 +vt 0.137241 0.145857 +vt 0.137241 0.200405 +vt 0.127910 0.140944 +vt 0.145924 0.158213 +vt 0.137241 0.200405 +vt 0.137241 0.145857 +vt 0.144900 0.097997 +vt 0.145924 0.158213 +vt 0.137241 0.145857 +vt 0.153536 0.111672 +vt 0.145924 0.158213 +vt 0.144900 0.097997 +vt 0.137341 0.266706 +vt 0.144765 0.278181 +vt 0.127910 0.278181 +vt 0.148833 0.262657 +vt 0.144765 0.278181 +vt 0.137341 0.266706 +vt 0.137341 0.239541 +vt 0.148833 0.262657 +vt 0.137341 0.266706 +vt 0.150715 0.239541 +vt 0.148833 0.262657 +vt 0.137341 0.239541 +vt 0.137241 0.200405 +vt 0.150715 0.239541 +vt 0.137341 0.239541 +vt 0.150045 0.209051 +vt 0.150715 0.239541 +vt 0.137241 0.200405 +vt 0.145924 0.158213 +vt 0.150045 0.209051 +vt 0.137241 0.200405 +vt 0.150013 0.165822 +vt 0.150045 0.209051 +vt 0.145924 0.158213 +vt 0.106106 0.262657 +vt 0.111729 0.278181 +vt 0.103181 0.262657 +vt 0.117872 0.265913 +vt 0.111729 0.278181 +vt 0.106106 0.262657 +vt 0.104336 0.239541 +vt 0.117872 0.265913 +vt 0.106106 0.262657 +vt 0.117872 0.239541 +vt 0.117872 0.265913 +vt 0.104336 0.239541 +vt 0.105372 0.209051 +vt 0.117872 0.239541 +vt 0.104336 0.239541 +vt 0.117761 0.200858 +vt 0.117872 0.239541 +vt 0.105372 0.209051 +vt 0.117647 0.098693 +vt 0.121934 0.145411 +vt 0.111422 0.161458 +vt 0.127910 0.140944 +vt 0.121934 0.145411 +vt 0.117647 0.098693 +vt 0.127839 0.093652 +vt 0.127910 0.140944 +vt 0.117647 0.098693 +vt 0.137241 0.145857 +vt 0.127910 0.140944 +vt 0.127839 0.093652 +vt 0.144900 0.097997 +vt 0.137241 0.145857 +vt 0.127839 0.093652 +vt 0.300505 0.205220 +vt 0.318364 0.180135 +vt 0.313031 0.205842 +vt 0.305174 0.173258 +vt 0.318364 0.180135 +vt 0.300505 0.205220 +vt 0.295828 0.168838 +vt 0.305174 0.173258 +vt 0.300505 0.205220 +vt 0.305174 0.092478 +vt 0.305174 0.173258 +vt 0.295828 0.168838 +vt 0.101340 0.239541 +vt 0.106106 0.262657 +vt 0.103181 0.262657 +vt 0.104336 0.239541 +vt 0.106106 0.262657 +vt 0.101340 0.239541 +vt 0.102327 0.209051 +vt 0.104336 0.239541 +vt 0.101340 0.239541 +vt 0.105372 0.209051 +vt 0.104336 0.239541 +vt 0.102327 0.209051 +vt 0.137341 0.239541 +vt 0.127910 0.204959 +vt 0.137241 0.200405 +vt 0.127910 0.245340 +vt 0.127910 0.204959 +vt 0.137341 0.239541 +vt 0.137341 0.266706 +vt 0.127910 0.245340 +vt 0.137341 0.239541 +vt 0.127910 0.278181 +vt 0.127910 0.245340 +vt 0.137341 0.266706 +vt 0.150045 0.209051 +vt 0.154167 0.209051 +vt 0.155154 0.239541 +vt 0.154163 0.169960 +vt 0.154167 0.209051 +vt 0.150045 0.209051 +vt 0.150013 0.165822 +vt 0.154163 0.169960 +vt 0.150045 0.209051 +vt 0.150013 0.165822 +vt 0.154167 0.209051 +vt 0.150045 0.209051 +vt 0.154163 0.169960 +vt 0.154167 0.209051 +vt 0.150013 0.165822 +vt 0.162115 0.127119 +vt 0.145924 0.158213 +vt 0.153536 0.111672 +vt 0.150013 0.165822 +vt 0.145924 0.158213 +vt 0.162115 0.127119 +vt 0.318364 0.092530 +vt 0.305174 0.173258 +vt 0.305174 0.092478 +vt 0.315441 0.173123 +vt 0.305174 0.173258 +vt 0.318364 0.092530 +vt 0.105424 0.183930 +vt 0.102327 0.209051 +vt 0.098683 0.169960 +vt 0.105372 0.209051 +vt 0.102327 0.209051 +vt 0.105424 0.183930 +vt 0.117872 0.265913 +vt 0.127910 0.278181 +vt 0.111729 0.278181 +vt 0.117872 0.239541 +vt 0.127910 0.278181 +vt 0.117872 0.265913 +vt 0.148833 0.262657 +vt 0.153313 0.262657 +vt 0.144765 0.278181 +vt 0.150715 0.239541 +vt 0.153313 0.262657 +vt 0.148833 0.262657 +vt 0.150715 0.239541 +vt 0.155154 0.239541 +vt 0.153313 0.262657 +vt 0.150045 0.209051 +vt 0.155154 0.239541 +vt 0.150715 0.239541 +vt 0.117872 0.239541 +vt 0.127910 0.245340 +vt 0.127910 0.278181 +vt 0.117761 0.200858 +vt 0.127910 0.245340 +vt 0.117872 0.239541 +vt 0.315441 0.173123 +vt 0.318364 0.180135 +vt 0.305174 0.173258 +vt 0.117761 0.200858 +vt 0.127910 0.204959 +vt 0.127910 0.245340 +vt 0.328644 0.163585 +vt 0.325105 0.162437 +vt 0.325105 0.165943 +vt 0.327626 0.160635 +vt 0.325105 0.162437 +vt 0.328644 0.163585 +vt 0.330110 0.155071 +vt 0.327626 0.160635 +vt 0.328644 0.163585 +vt 0.328590 0.155071 +vt 0.327626 0.160635 +vt 0.330110 0.155071 +vt 0.328644 0.146746 +vt 0.328590 0.155071 +vt 0.330110 0.155071 +vt 0.327626 0.150294 +vt 0.328590 0.155071 +vt 0.328644 0.146746 +vt 0.325105 0.144389 +vt 0.327626 0.150294 +vt 0.328644 0.146746 +vt 0.325105 0.148683 +vt 0.327626 0.150294 +vt 0.325105 0.144389 +vt 0.321622 0.146746 +vt 0.325105 0.148683 +vt 0.325105 0.144389 +vt 0.322802 0.150035 +vt 0.325105 0.148683 +vt 0.321622 0.146746 +vt 0.320100 0.155071 +vt 0.322802 0.150035 +vt 0.321622 0.146746 +vt 0.321622 0.155071 +vt 0.322802 0.150035 +vt 0.320100 0.155071 +vt 0.321622 0.162900 +vt 0.321622 0.155071 +vt 0.320100 0.155071 +vt 0.322585 0.160635 +vt 0.321622 0.155071 +vt 0.321622 0.162900 +vt 0.325105 0.165943 +vt 0.322585 0.160635 +vt 0.321622 0.162900 +vt 0.325105 0.162437 +vt 0.322585 0.160635 +vt 0.325105 0.165943 +vt 0.328644 0.163585 +vt 0.325105 0.162437 +vt 0.325105 0.165943 +vt 0.327626 0.160635 +vt 0.325105 0.162437 +vt 0.328644 0.163585 +vt 0.330110 0.155071 +vt 0.327626 0.160635 +vt 0.328644 0.163585 +vt 0.328590 0.155071 +vt 0.327626 0.160635 +vt 0.330110 0.155071 +vt 0.328644 0.146746 +vt 0.328590 0.155071 +vt 0.330110 0.155071 +vt 0.327626 0.150294 +vt 0.328590 0.155071 +vt 0.328644 0.146746 +vt 0.325105 0.144389 +vt 0.327626 0.150294 +vt 0.328644 0.146746 +vt 0.325105 0.148683 +vt 0.327626 0.150294 +vt 0.325105 0.144389 +vt 0.321622 0.146746 +vt 0.325105 0.148683 +vt 0.325105 0.144389 +vt 0.322802 0.150035 +vt 0.325105 0.148683 +vt 0.321622 0.146746 +vt 0.320100 0.155071 +vt 0.322802 0.150035 +vt 0.321622 0.146746 +vt 0.321622 0.155071 +vt 0.322802 0.150035 +vt 0.320100 0.155071 +vt 0.321622 0.162900 +vt 0.321622 0.155071 +vt 0.320100 0.155071 +vt 0.322585 0.160635 +vt 0.321622 0.155071 +vt 0.321622 0.162900 +vt 0.325105 0.165943 +vt 0.322585 0.160635 +vt 0.321622 0.162900 +vt 0.325105 0.162437 +vt 0.322585 0.160635 +vt 0.325105 0.165943 +vt 0.329919 0.110144 +vt 0.326298 0.108797 +vt 0.326366 0.112944 +vt 0.328634 0.107162 +vt 0.326298 0.108797 +vt 0.329919 0.110144 +vt 0.331391 0.103384 +vt 0.328634 0.107162 +vt 0.329919 0.110144 +vt 0.329601 0.103214 +vt 0.328634 0.107162 +vt 0.331391 0.103384 +vt 0.329919 0.096624 +vt 0.329601 0.103214 +vt 0.331391 0.103384 +vt 0.328634 0.099267 +vt 0.329601 0.103214 +vt 0.329919 0.096624 +vt 0.326366 0.093824 +vt 0.328634 0.099267 +vt 0.329919 0.096624 +vt 0.326298 0.097632 +vt 0.328634 0.099267 +vt 0.326366 0.093824 +vt 0.322813 0.096624 +vt 0.326298 0.097632 +vt 0.326366 0.093824 +vt 0.323963 0.099267 +vt 0.326298 0.097632 +vt 0.322813 0.096624 +vt 0.321341 0.103384 +vt 0.323963 0.099267 +vt 0.322813 0.096624 +vt 0.322996 0.103214 +vt 0.323963 0.099267 +vt 0.321341 0.103384 +vt 0.322813 0.110144 +vt 0.322996 0.103214 +vt 0.321341 0.103384 +vt 0.323963 0.107162 +vt 0.322996 0.103214 +vt 0.322813 0.110144 +vt 0.326366 0.112944 +vt 0.323963 0.107162 +vt 0.322813 0.110144 +vt 0.326298 0.108797 +vt 0.323963 0.107162 +vt 0.326366 0.112944 +vt 0.202254 0.100692 +vt 0.186427 0.164558 +vt 0.186420 0.100694 +vt 0.202203 0.164222 +vt 0.186427 0.164558 +vt 0.202254 0.100692 +vt 0.223928 0.090362 +vt 0.202203 0.164222 +vt 0.202254 0.100692 +vt 0.224053 0.164170 +vt 0.202203 0.164222 +vt 0.223928 0.090362 +vt 0.237556 0.165400 +vt 0.224053 0.164170 +vt 0.223928 0.090362 +vt 0.237497 0.195760 +vt 0.224053 0.164170 +vt 0.237556 0.165400 +vt 0.241414 0.166630 +vt 0.237497 0.195760 +vt 0.237556 0.165400 +vt 0.246034 0.168263 +vt 0.237497 0.195760 +vt 0.241414 0.166630 +vt 0.248304 0.095228 +vt 0.246034 0.168263 +vt 0.241414 0.166630 +vt 0.260205 0.170870 +vt 0.246034 0.168263 +vt 0.248304 0.095228 +vt 0.269172 0.098910 +vt 0.260205 0.170870 +vt 0.248304 0.095228 +vt 0.275533 0.170960 +vt 0.260205 0.170870 +vt 0.269172 0.098910 +vt 0.288985 0.099711 +vt 0.275533 0.170960 +vt 0.269172 0.098910 +vt 0.290619 0.168724 +vt 0.275533 0.170960 +vt 0.288985 0.099711 +vt 0.309843 0.355889 +vt 0.315335 0.357743 +vt 0.315335 0.370618 +vt 0.309843 0.330748 +vt 0.315335 0.357743 +vt 0.309843 0.355889 +vt 0.300443 0.331309 +vt 0.309843 0.330748 +vt 0.309843 0.355889 +vt 0.300443 0.283009 +vt 0.309843 0.330748 +vt 0.300443 0.331309 +vt 0.293098 0.283009 +vt 0.300443 0.283009 +vt 0.300443 0.331309 +vt 0.293098 0.272168 +vt 0.300443 0.283009 +vt 0.285634 0.272168 +vt 0.293098 0.272168 +vt 0.284645 0.212164 +vt 0.293098 0.272168 +vt 0.285634 0.272168 +vt 0.295828 0.168838 +vt 0.288985 0.099711 +vt 0.305174 0.092478 +vt 0.290619 0.168724 +vt 0.288985 0.099711 +vt 0.295828 0.168838 +vt 0.300505 0.205220 +vt 0.290619 0.168724 +vt 0.295828 0.168838 +vt 0.291683 0.206035 +vt 0.290619 0.168724 +vt 0.300505 0.205220 +vt 0.293098 0.228026 +vt 0.291683 0.206035 +vt 0.300505 0.205220 +vt 0.284645 0.212164 +vt 0.291683 0.206035 +vt 0.293098 0.228026 +vt 0.293098 0.272168 +vt 0.284645 0.212164 +vt 0.293098 0.228026 +vt 0.284645 0.212164 +vt 0.290619 0.168724 +vt 0.291683 0.206035 +vt 0.275533 0.170960 +vt 0.290619 0.168724 +vt 0.284645 0.212164 +vt 0.275736 0.210912 +vt 0.275533 0.170960 +vt 0.284645 0.212164 +vt 0.267980 0.214975 +vt 0.275533 0.170960 +vt 0.275736 0.210912 +vt 0.275855 0.232448 +vt 0.267980 0.214975 +vt 0.275736 0.210912 +vt 0.275896 0.275758 +vt 0.267980 0.214975 +vt 0.275855 0.232448 +vt 0.283285 0.275758 +vt 0.275896 0.275758 +vt 0.275855 0.232448 +vt 0.309843 0.330748 +vt 0.315335 0.333274 +vt 0.315335 0.357743 +vt 0.309843 0.272168 +vt 0.315335 0.333274 +vt 0.309843 0.330748 +vt 0.300443 0.283009 +vt 0.309843 0.272168 +vt 0.309843 0.330748 +vt 0.300443 0.272168 +vt 0.309843 0.272168 +vt 0.300443 0.283009 +vt 0.293098 0.272168 +vt 0.300443 0.272168 +vt 0.300443 0.283009 +vt 0.293098 0.228026 +vt 0.300443 0.272168 +vt 0.293098 0.272168 +vt 0.246034 0.168263 +vt 0.244660 0.198728 +vt 0.237497 0.195760 +vt 0.252838 0.207011 +vt 0.244660 0.198728 +vt 0.246034 0.168263 +vt 0.260205 0.170870 +vt 0.252838 0.207011 +vt 0.246034 0.168263 +vt 0.260309 0.208336 +vt 0.252838 0.207011 +vt 0.260205 0.170870 +vt 0.267980 0.214975 +vt 0.260309 0.208336 +vt 0.260205 0.170870 +vt 0.285634 0.283009 +vt 0.285634 0.272168 +vt 0.293098 0.334137 +vt 0.300443 0.331309 +vt 0.300443 0.356185 +vt 0.300443 0.331309 +vt 0.309843 0.355889 +vt 0.300443 0.356185 +vt 0.300443 0.331309 +vt 0.227442 0.198295 +vt 0.224053 0.164170 +vt 0.237497 0.195760 +vt 0.202203 0.164222 +vt 0.224053 0.164170 +vt 0.227442 0.198295 +vt 0.196936 0.203490 +vt 0.202203 0.164222 +vt 0.227442 0.198295 +vt 0.186427 0.164558 +vt 0.202203 0.164222 +vt 0.196936 0.203490 +vt 0.182199 0.212576 +vt 0.196936 0.203490 +vt 0.190329 0.229401 +vt 0.186427 0.164558 +vt 0.196936 0.203490 +vt 0.182199 0.212576 +vt 0.169600 0.140939 +vt 0.186427 0.164558 +vt 0.182199 0.212576 +vt 0.186420 0.100694 +vt 0.186427 0.164558 +vt 0.169600 0.140939 +vt 0.331166 0.330748 +vt 0.321084 0.272168 +vt 0.331166 0.283659 +vt 0.321084 0.330748 +vt 0.321084 0.272168 +vt 0.331166 0.355889 +vt 0.321084 0.355889 +vt 0.315335 0.205842 +vt 0.309843 0.272168 +vt 0.313031 0.205842 +vt 0.315335 0.272168 +vt 0.309843 0.272168 +vt 0.315335 0.205842 +vt 0.313031 0.205842 +vt 0.315335 0.272168 +vt 0.315335 0.205842 +vt 0.309843 0.272168 +vt 0.315335 0.272168 +vt 0.313031 0.205842 +vt 0.321084 0.205842 +vt 0.315335 0.272168 +vt 0.315335 0.205842 +vt 0.321084 0.272168 +vt 0.315335 0.272168 +vt 0.321084 0.205842 +vt 0.331166 0.272168 +vt 0.321084 0.272168 +vt 0.321084 0.205842 +vt 0.321084 0.272168 +vt 0.331166 0.272168 +vt 0.325105 0.155071 +vt 0.325105 0.148683 +vt 0.322802 0.150035 +vt 0.327626 0.150294 +vt 0.325105 0.148683 +vt 0.325105 0.155071 +vt 0.328590 0.155071 +vt 0.327626 0.150294 +vt 0.325105 0.155071 +vt 0.169600 0.140939 +vt 0.150013 0.165822 +vt 0.162115 0.127119 +vt 0.154163 0.169960 +vt 0.150013 0.165822 +vt 0.169600 0.140939 +vt 0.154167 0.209051 +vt 0.154163 0.169960 +vt 0.169600 0.140939 +vt 0.167478 0.215172 +vt 0.182199 0.212576 +vt 0.175952 0.232554 +vt 0.169600 0.140939 +vt 0.182199 0.212576 +vt 0.167478 0.215172 +vt 0.154167 0.209051 +vt 0.169600 0.140939 +vt 0.167478 0.215172 +vt 0.309843 0.272168 +vt 0.315335 0.272168 +vt 0.315335 0.333274 +vt 0.315335 0.205842 +vt 0.315335 0.272168 +vt 0.309843 0.272168 +vt 0.313031 0.205842 +vt 0.315335 0.205842 +vt 0.309843 0.272168 +vt 0.309854 0.392718 +vt 0.321083 0.392718 +vt 0.309843 0.355889 +vt 0.309854 0.392718 +vt 0.300443 0.392718 +vt 0.309843 0.355889 +vt 0.309854 0.392718 +vt 0.315335 0.272168 +vt 0.321084 0.272168 +vt 0.315335 0.333358 +vt 0.315335 0.272168 +vt 0.326366 0.103142 +vt 0.326298 0.097632 +vt 0.323963 0.099267 +vt 0.328634 0.099267 +vt 0.326298 0.097632 +vt 0.326366 0.103142 +vt 0.329601 0.103214 +vt 0.328634 0.099267 +vt 0.326366 0.103142 +vt 0.325105 0.155071 +vt 0.325105 0.148683 +vt 0.322802 0.150035 +vt 0.327626 0.150294 +vt 0.325105 0.148683 +vt 0.325105 0.155071 +vt 0.328590 0.155071 +vt 0.327626 0.150294 +vt 0.325105 0.155071 +vt 0.321083 0.392718 +vt 0.331166 0.392718 +vt 0.315335 0.370701 +vt 0.321083 0.392718 +vt 0.285634 0.355064 +vt 0.289768 0.368554 +vt 0.285634 0.329344 +vt 0.309843 0.272168 +vt 0.300505 0.205220 +vt 0.313031 0.205842 +vt 0.300443 0.272168 +vt 0.300505 0.205220 +vt 0.309843 0.272168 +vt 0.300443 0.272168 +vt 0.313031 0.205842 +vt 0.300505 0.205220 +vt 0.309843 0.272168 +vt 0.313031 0.205842 +vt 0.300443 0.272168 +vt 0.241414 0.166630 +vt 0.237506 0.092795 +vt 0.248304 0.095228 +vt 0.237556 0.165400 +vt 0.237506 0.092795 +vt 0.241414 0.166630 +vt 0.322996 0.103214 +vt 0.326366 0.103142 +vt 0.323963 0.099267 +vt 0.323963 0.107162 +vt 0.326366 0.103142 +vt 0.322996 0.103214 +vt 0.326298 0.108797 +vt 0.326366 0.103142 +vt 0.323963 0.107162 +vt 0.328634 0.107162 +vt 0.326366 0.103142 +vt 0.326298 0.108797 +vt 0.284645 0.212164 +vt 0.275855 0.232448 +vt 0.275736 0.210912 +vt 0.283285 0.275758 +vt 0.275855 0.232448 +vt 0.284645 0.212164 +vt 0.296881 0.368554 +vt 0.300443 0.356185 +vt 0.321622 0.155071 +vt 0.325105 0.155071 +vt 0.322802 0.150035 +vt 0.322585 0.160635 +vt 0.325105 0.155071 +vt 0.321622 0.155071 +vt 0.325105 0.162437 +vt 0.325105 0.155071 +vt 0.322585 0.160635 +vt 0.327626 0.160635 +vt 0.325105 0.155071 +vt 0.325105 0.162437 +vt 0.315335 0.357827 +vt 0.315335 0.370701 +vt 0.300505 0.205220 +vt 0.309843 0.272168 +vt 0.300443 0.272168 +vt 0.313031 0.205842 +vt 0.309843 0.272168 +vt 0.300505 0.205220 +vt 0.321622 0.155071 +vt 0.325105 0.155071 +vt 0.322802 0.150035 +vt 0.322585 0.160635 +vt 0.325105 0.155071 +vt 0.321622 0.155071 +vt 0.325105 0.162437 +vt 0.325105 0.155071 +vt 0.322585 0.160635 +vt 0.327626 0.160635 +vt 0.325105 0.155071 +vt 0.325105 0.162437 +vt 0.167478 0.215172 +vt 0.160076 0.231531 +vt 0.154167 0.209051 +vt 0.269076 0.275758 +vt 0.267980 0.214975 +vt 0.275896 0.275758 +vt 0.260205 0.170870 +vt 0.275533 0.170960 +vt 0.267980 0.214975 +vt 0.223928 0.090362 +vt 0.237506 0.092795 +vt 0.237556 0.165400 +vt 0.321084 0.205842 +vt 0.331166 0.205842 +vt 0.331166 0.272168 +vt 0.293098 0.228026 +vt 0.300505 0.205220 +vt 0.300443 0.272168 +vt 0.328634 0.107162 +vt 0.329601 0.103214 +vt 0.326366 0.103142 +vt 0.327626 0.160635 +vt 0.328590 0.155071 +vt 0.325105 0.155071 +vt 0.327626 0.160635 +vt 0.328590 0.155071 +vt 0.325105 0.155071 +vt 0.315335 0.370618 +vt 0.309854 0.392718 +vt 0.321083 0.392718 +vt 0.309843 0.355889 +vt 0.309854 0.392718 +vt 0.315335 0.370618 +vt 0.315335 0.357743 +vt 0.309843 0.355889 +vt 0.315335 0.370618 +vt 0.309843 0.330748 +vt 0.309843 0.355889 +vt 0.315335 0.357743 +vt 0.315335 0.333274 +vt 0.309843 0.330748 +vt 0.315335 0.357743 +vt 0.309843 0.272168 +vt 0.309843 0.330748 +vt 0.315335 0.333274 +vt 0.315335 0.272168 +vt 0.309843 0.272168 +vt 0.315335 0.333274 +vt 0.309843 0.272168 +vt 0.300443 0.283009 +vt 0.300443 0.272168 +vt 0.309843 0.330748 +vt 0.300443 0.283009 +vt 0.309843 0.272168 +vt 0.315335 0.333274 +vt 0.309843 0.330748 +vt 0.309843 0.272168 +vt 0.315335 0.357743 +vt 0.309843 0.330748 +vt 0.315335 0.333274 +vt 0.309843 0.355889 +vt 0.315335 0.357743 +vt 0.315335 0.333274 +vt 0.315335 0.370701 +vt 0.315335 0.357743 +vt 0.309843 0.355889 +vt 0.309854 0.392718 +vt 0.315335 0.370701 +vt 0.309843 0.355889 +vt 0.283285 0.286898 +vt 0.275896 0.275758 +vt 0.283285 0.275758 +vt 0.275896 0.286898 +vt 0.275896 0.275758 +vt 0.283285 0.286898 +vt 0.283285 0.327944 +vt 0.275896 0.286898 +vt 0.283285 0.286898 +vt 0.275896 0.331871 +vt 0.275896 0.286898 +vt 0.283285 0.327944 +vt 0.283285 0.361917 +vt 0.275896 0.331871 +vt 0.283285 0.327944 +vt 0.280069 0.373285 +vt 0.275896 0.331871 +vt 0.283285 0.361917 +vt 0.331166 0.283659 +vt 0.331166 0.330748 +vt 0.331166 0.283659 +vt 0.321084 0.330748 +vt 0.331166 0.330748 +vt 0.331166 0.355889 +vt 0.331166 0.330748 +vt 0.321084 0.330748 +vt 0.321084 0.355889 +vt 0.331166 0.355889 +vt 0.321084 0.330748 +vt 0.300443 0.331309 +vt 0.293098 0.334137 +vt 0.300443 0.356185 +vt 0.293098 0.283009 +vt 0.293098 0.334137 +vt 0.300443 0.331309 +vt 0.300443 0.283009 +vt 0.293098 0.283009 +vt 0.300443 0.331309 +vt 0.293098 0.283009 +vt 0.300443 0.283009 +vt 0.300443 0.283009 +vt 0.300443 0.283009 +vt 0.309843 0.272168 +vt 0.309843 0.330748 +vt 0.309843 0.272168 +vt 0.300443 0.283009 +vt 0.300443 0.331309 +vt 0.309843 0.330748 +vt 0.300443 0.283009 +vt 0.309843 0.355889 +vt 0.309843 0.330748 +vt 0.300443 0.331309 +vt 0.300443 0.356185 +vt 0.309843 0.355889 +vt 0.300443 0.331309 +vt 0.309843 0.355889 +vt 0.315335 0.357743 +vt 0.315335 0.370701 +vt 0.309843 0.330748 +vt 0.315335 0.357743 +vt 0.309843 0.355889 +vt 0.300443 0.331309 +vt 0.309843 0.330748 +vt 0.309843 0.355889 +vt 0.300443 0.283009 +vt 0.309843 0.330748 +vt 0.300443 0.331309 +vt 0.315335 0.272168 +vt 0.315335 0.333274 +vt 0.309843 0.272168 +vt 0.309843 0.330748 +vt 0.315335 0.333274 +vt 0.315335 0.272168 +vt 0.309843 0.272168 +vt 0.309843 0.330748 +vt 0.315335 0.272168 +vt 0.300443 0.331309 +vt 0.309843 0.330748 +vt 0.309843 0.272168 +vt 0.321084 0.355889 +vt 0.321083 0.392718 +vt 0.331166 0.392718 +vt 0.315335 0.370701 +vt 0.321083 0.392718 +vt 0.321084 0.355889 +vt 0.315335 0.357827 +vt 0.315335 0.370701 +vt 0.321084 0.355889 +vt 0.309854 0.392718 +vt 0.315335 0.370701 +vt 0.321083 0.392718 +vt 0.309843 0.355889 +vt 0.315335 0.370701 +vt 0.309854 0.392718 +vt 0.300443 0.392718 +vt 0.309843 0.355889 +vt 0.309854 0.392718 +vt 0.275896 0.286898 +vt 0.269076 0.275758 +vt 0.275896 0.275758 +vt 0.269076 0.286898 +vt 0.269076 0.275758 +vt 0.275896 0.286898 +vt 0.275896 0.331871 +vt 0.269076 0.286898 +vt 0.275896 0.286898 +vt 0.309843 0.330748 +vt 0.309843 0.355889 +vt 0.315335 0.333274 +vt 0.300443 0.356185 +vt 0.309843 0.355889 +vt 0.309843 0.330748 +vt 0.300443 0.331309 +vt 0.300443 0.356185 +vt 0.309843 0.330748 +vt 0.293098 0.334137 +vt 0.285634 0.355064 +vt 0.289768 0.368554 +vt 0.285634 0.329344 +vt 0.285634 0.355064 +vt 0.293098 0.334137 +vt 0.285634 0.283009 +vt 0.285634 0.329344 +vt 0.293098 0.334137 +vt 0.300443 0.283009 +vt 0.309843 0.272168 +vt 0.300443 0.272168 +vt 0.300443 0.331309 +vt 0.309843 0.272168 +vt 0.300443 0.283009 +vt 0.272112 0.373285 +vt 0.275896 0.331871 +vt 0.280069 0.373285 +vt 0.269076 0.362842 +vt 0.275896 0.331871 +vt 0.272112 0.373285 +vt 0.269076 0.327861 +vt 0.275896 0.331871 +vt 0.269076 0.362842 +vt 0.269076 0.286898 +vt 0.275896 0.331871 +vt 0.269076 0.327861 +vt 0.315335 0.272168 +vt 0.321084 0.330748 +vt 0.315335 0.333358 +vt 0.321084 0.330748 +vt 0.315335 0.272168 +vt 0.315335 0.333358 +vt 0.321084 0.355889 +vt 0.321084 0.330748 +vt 0.315335 0.357827 +vt 0.321084 0.355889 +vt 0.315335 0.333358 +vt 0.296881 0.368554 +vt 0.293098 0.334137 +vt 0.289768 0.368554 +vt 0.300443 0.356185 +vt 0.293098 0.334137 +vt 0.296881 0.368554 +vt 0.293098 0.283009 +vt 0.285634 0.283009 +vt 0.293098 0.283009 +vt 0.309854 0.392718 +vt 0.309843 0.355889 +vt 0.300443 0.392718 +vt 0.309843 0.355889 +vt 0.300443 0.392718 +vt 0.309854 0.392718 +vt 0.309843 0.355889 +vt 0.300443 0.356185 +vt 0.300443 0.331309 +vt 0.293098 0.334137 +vt 0.293098 0.283009 +vt 0.285634 0.283009 +vt 0.227442 0.198295 +vt 0.221458 0.256750 +vt 0.221458 0.202322 +vt 0.227442 0.256750 +vt 0.221458 0.256750 +vt 0.227442 0.198295 +vt 0.237497 0.256028 +vt 0.227442 0.256750 +vt 0.227442 0.198295 +vt 0.237497 0.266660 +vt 0.227442 0.256750 +vt 0.237497 0.256028 +vt 0.244660 0.266660 +vt 0.237497 0.266660 +vt 0.237497 0.256028 +vt 0.244660 0.308322 +vt 0.237497 0.266660 +vt 0.244660 0.266660 +vt 0.252378 0.305580 +vt 0.244660 0.308322 +vt 0.244660 0.266660 +vt 0.252378 0.332716 +vt 0.244660 0.308322 +vt 0.206100 0.303375 +vt 0.215533 0.330059 +vt 0.206100 0.330059 +vt 0.215533 0.303375 +vt 0.215533 0.330059 +vt 0.206100 0.303375 +vt 0.206100 0.266660 +vt 0.215533 0.303375 +vt 0.206100 0.303375 +vt 0.215533 0.256750 +vt 0.215533 0.303375 +vt 0.206100 0.266660 +vt 0.206100 0.256750 +vt 0.215533 0.256750 +vt 0.206100 0.266660 +vt 0.206100 0.204278 +vt 0.215533 0.256750 +vt 0.206100 0.256750 +vt 0.227442 0.363326 +vt 0.227442 0.330059 +vt 0.237497 0.363326 +vt 0.221457 0.345892 +vt 0.227442 0.330059 +vt 0.227442 0.363326 +vt 0.215533 0.363326 +vt 0.221457 0.345892 +vt 0.227442 0.363326 +vt 0.215533 0.330059 +vt 0.221457 0.345892 +vt 0.215533 0.363326 +vt 0.206100 0.363326 +vt 0.215533 0.330059 +vt 0.215533 0.363326 +vt 0.237497 0.330059 +vt 0.244660 0.308322 +vt 0.241246 0.341147 +vt 0.237497 0.302945 +vt 0.244660 0.308322 +vt 0.237497 0.330059 +vt 0.227442 0.303375 +vt 0.237497 0.302945 +vt 0.237497 0.330059 +vt 0.227442 0.256750 +vt 0.237497 0.302945 +vt 0.227442 0.303375 +vt 0.221458 0.256750 +vt 0.227442 0.256750 +vt 0.227442 0.303375 +vt 0.237497 0.195760 +vt 0.237497 0.256028 +vt 0.227442 0.198295 +vt 0.244660 0.256028 +vt 0.237497 0.256028 +vt 0.237497 0.195760 +vt 0.244660 0.216971 +vt 0.244660 0.256028 +vt 0.237497 0.195760 +vt 0.252378 0.256028 +vt 0.244660 0.256028 +vt 0.244660 0.216971 +vt 0.252838 0.207011 +vt 0.244660 0.216971 +vt 0.221458 0.256750 +vt 0.215533 0.256750 +vt 0.221458 0.202334 +vt 0.221458 0.303375 +vt 0.215533 0.256750 +vt 0.221458 0.256750 +vt 0.227442 0.303375 +vt 0.221458 0.303375 +vt 0.221458 0.256750 +vt 0.227442 0.330059 +vt 0.221458 0.303375 +vt 0.227442 0.303375 +vt 0.237497 0.330059 +vt 0.227442 0.330059 +vt 0.227442 0.303375 +vt 0.221458 0.303375 +vt 0.215533 0.303375 +vt 0.215533 0.256750 +vt 0.221458 0.330059 +vt 0.215533 0.303375 +vt 0.221458 0.303375 +vt 0.227442 0.330059 +vt 0.221458 0.330059 +vt 0.221458 0.303375 +vt 0.221457 0.345892 +vt 0.221458 0.330059 +vt 0.227442 0.330059 +vt 0.252378 0.266660 +vt 0.244660 0.256028 +vt 0.244660 0.266660 +vt 0.244660 0.256028 +vt 0.244660 0.266660 +vt 0.248396 0.341147 +vt 0.244660 0.308322 +vt 0.241246 0.341147 +vt 0.244660 0.308322 +vt 0.248396 0.341147 +vt 0.244660 0.216971 +vt 0.244660 0.198728 +vt 0.252838 0.207011 +vt 0.237497 0.195760 +vt 0.244660 0.198728 +vt 0.244660 0.216971 +vt 0.215533 0.206439 +vt 0.215533 0.256750 +vt 0.206100 0.204278 +vt 0.221458 0.202334 +vt 0.215533 0.256750 +vt 0.215533 0.206439 +vt 0.215533 0.330059 +vt 0.221458 0.330059 +vt 0.221457 0.345892 +vt 0.215533 0.303375 +vt 0.221458 0.330059 +vt 0.215533 0.330059 +vt 0.237497 0.302945 +vt 0.237497 0.266660 +vt 0.244660 0.308322 +vt 0.227442 0.256750 +vt 0.237497 0.266660 +vt 0.237497 0.302945 +vt 0.244660 0.256028 +vt 0.244660 0.266660 +vt 0.237497 0.256028 +vt 0.049142 0.137390 +vt 0.053973 0.137696 +vt 0.054364 0.090769 +vt 0.053769 0.177667 +vt 0.049266 0.178033 +vt 0.054212 0.210563 +vt 0.049702 0.210261 +vt 0.054521 0.232047 +vt 0.049760 0.231373 +vt 0.055087 0.243166 +vt 0.049813 0.242143 +vt 0.055200 0.245183 +vt 0.049954 0.244040 +vt 0.054968 0.240195 +vt 0.049837 0.238845 +vt 0.054284 0.223758 +vt 0.049521 0.222472 +vt 0.053892 0.200197 +vt 0.049382 0.199965 +vt 0.053449 0.168970 +vt 0.048949 0.170032 +vt 0.053684 0.129969 +vt 0.048851 0.129856 +vt 0.054363 0.090460 +vt 0.088190 0.118157 +vt 0.086262 0.087844 +vt 0.088681 0.147864 +vt 0.083635 0.059266 +vt 0.089114 0.121254 +vt 0.088303 0.118202 +vt 0.089826 0.150465 +vt 0.088843 0.148016 +vt 0.090378 0.183657 +vt 0.088702 0.178117 +vt 0.082783 0.219790 +vt 0.081264 0.205141 +vt 0.071173 0.228579 +vt 0.078824 0.170985 +vt 0.070332 0.176781 +vt 0.076675 0.134214 +vt 0.068387 0.134949 +vt 0.071429 0.046744 +vt 0.064424 0.044403 +vt 0.070956 0.025454 +vt 0.064282 0.021547 +vt 0.070786 0.009444 +vt 0.064454 0.006899 +vt 0.070956 0.025454 +vt 0.075079 0.255271 +vt 0.062004 0.250551 +vt 0.062018 0.256899 +vt 0.073343 0.245831 +vt 0.082783 0.219790 +vt 0.081264 0.205141 +vt 0.082783 0.219790 +vt 0.088482 0.177915 +vt 0.081264 0.205141 +vt 0.082783 0.219790 +vt 0.085696 0.176279 +vt 0.081264 0.205141 +vt 0.083506 0.136857 +vt 0.075074 0.088814 +vt 0.079424 0.055474 +vt 0.071039 0.046988 +vt 0.070956 0.025454 +vt 0.064282 0.021547 +vt 0.070956 0.025454 +vt 0.064282 0.021547 +vt 0.070956 0.025454 +vt 0.058783 0.009351 +vt 0.064282 0.021547 +vt 0.058097 0.022524 +vt 0.054028 0.024477 +vt 0.053899 0.033683 +vt 0.041896 0.129560 +vt 0.006571 0.088691 +vt 0.037621 0.088349 +vt 0.003725 0.129572 +vt 0.043004 0.173889 +vt 0.001337 0.174427 +vt 0.041805 0.207061 +vt 0.003682 0.210131 +vt 0.037128 0.231930 +vt 0.009436 0.233428 +vt 0.030731 0.250106 +vt 0.060397 0.241334 +vt 0.071173 0.228579 +vt 0.060049 0.217383 +vt 0.071173 0.228579 +vt 0.069733 0.178151 +vt 0.071173 0.228579 +vt 0.059453 0.180977 +vt 0.059800 0.138836 +vt 0.059960 0.128948 +vt 0.059566 0.170152 +vt 0.060086 0.205962 +vt 0.060448 0.232782 +vt 0.062492 0.244204 +vt 0.054488 0.017666 +vt 0.058097 0.022524 +vt 0.054028 0.024477 +vt 0.058097 0.022524 +vt 0.057772 0.034243 +vt 0.058097 0.022524 +vt 0.054028 0.024477 +vt 0.053903 0.035082 +vt 0.054028 0.024477 +vt 0.057658 0.047876 +vt 0.053947 0.052426 +vt 0.057772 0.033755 +vt 0.058013 0.047616 +vt 0.048905 0.033618 +vt 0.048952 0.052171 +vt 0.048953 0.021912 +vt 0.048899 0.017646 +vt 0.054028 0.024477 +vt 0.048850 0.021973 +vt 0.054028 0.024477 +vt 0.078952 0.025162 +vt 0.079736 0.055277 +vt 0.086427 0.087492 +vt 0.067004 0.090294 +vt 0.063950 0.044658 +vt 0.076114 0.135138 +vt 0.067765 0.135911 +vt 0.078308 0.172299 +vt 0.071173 0.228579 +vt 0.062004 0.250551 +vt 0.062004 0.250551 +vt 0.073343 0.245831 +vt 0.088100 0.235740 +vt 0.073343 0.245831 +vt 0.073343 0.245831 +vt 0.060065 0.089841 +vt 0.007046 0.044053 +vt 0.036709 0.085389 +vt 0.007020 0.085818 +vt 0.035781 0.043961 +vt 0.009346 0.025038 +vt 0.032185 0.023489 +vt 0.014510 0.010630 +vt 0.078820 0.025248 +vt 0.053947 0.052266 +vt 0.082783 0.219790 +vt 0.082783 0.219790 +vt 0.083864 0.136344 +vt 0.086038 0.176142 +vt 0.049049 0.089716 +vt 0.064282 0.021547 +vt 0.064282 0.021547 +vt 0.048952 0.052254 +vt 0.049050 0.090105 +vt 0.016024 0.249962 +vt 0.023409 0.255880 +vt 0.048908 0.035022 +vt 0.054028 0.024477 +vt 0.070956 0.025454 +vt 0.070956 0.025454 +vt 0.062004 0.250551 +vt 0.061863 0.254876 +vt 0.062004 0.250551 +vt 0.071173 0.228579 +vt 0.081264 0.205141 +vt 0.071173 0.228579 +vt 0.058097 0.022524 +vt 0.064282 0.021547 +vt 0.064282 0.021547 +vt 0.058097 0.022524 +vt 0.026927 0.010604 +vt 0.021004 0.005880 +vt 0.073343 0.245831 +vt 0.073343 0.245831 +vt 0.081264 0.205141 +vt 0.071173 0.228579 +vt 0.081264 0.205141 +vt 0.288695 0.485509 +vt 0.280415 0.493664 +vt 0.288695 0.493811 +vt 0.283742 0.486120 +vt 0.288695 0.478083 +vt 0.283210 0.478974 +vt 0.283041 0.472550 +vt 0.286608 0.467560 +vt 0.288695 0.472076 +vt 0.286608 0.467560 +vt 0.286849 0.466197 +vt 0.286608 0.467560 +vt 0.283041 0.472550 +vt 0.286608 0.467560 +vt 0.283210 0.478974 +vt 0.283041 0.472550 +vt 0.283742 0.486120 +vt 0.283210 0.478974 +vt 0.280415 0.493664 +vt 0.283742 0.486120 +vt 0.280415 0.493664 +vt 0.288695 0.469781 +vt 0.286849 0.466197 +vt 0.286849 0.466197 +vt 0.283742 0.486120 +vt 0.279559 0.488823 +vt 0.283742 0.486120 +vt 0.280415 0.493664 +vt 0.283210 0.478974 +vt 0.283742 0.486120 +vt 0.278641 0.482666 +vt 0.283210 0.478974 +vt 0.283041 0.472550 +vt 0.283210 0.478974 +vt 0.280177 0.469963 +vt 0.283041 0.472550 +vt 0.283002 0.466748 +vt 0.283041 0.472550 +vt 0.283064 0.465472 +vt 0.286849 0.466197 +vt 0.280080 0.469047 +vt 0.283064 0.465472 +vt 0.278318 0.475533 +vt 0.286849 0.466197 +vt 0.286849 0.466197 +vt 0.281092 0.495183 +vt 0.278259 0.477544 +vt 0.280177 0.469963 +vt 0.278641 0.482666 +vt 0.280177 0.469963 +vt 0.280177 0.469963 +vt 0.278641 0.482666 +vt 0.280177 0.469963 +vt 0.283064 0.465472 +vt 0.283002 0.466748 +vt 0.283064 0.465472 +vt 0.280177 0.469963 +vt 0.283002 0.466748 +vt 0.280177 0.469963 +vt 0.283002 0.466748 +vt 0.278259 0.477544 +vt 0.280080 0.469047 +vt 0.278259 0.477544 +vt 0.278318 0.475533 +vt 0.280080 0.469047 +vt 0.278259 0.477544 +vt 0.281092 0.495183 +vt 0.278318 0.475533 +vt 0.281092 0.495183 +vt 0.278318 0.475533 +vt 0.279559 0.488823 +vt 0.279559 0.488823 +vt 0.286608 0.467560 +vt 0.283041 0.472550 +vt 0.286608 0.467560 +vt 0.280080 0.469047 +vt 0.278318 0.475533 +vt 0.280080 0.469047 +vt 0.278641 0.482666 +vt 0.279559 0.488823 +vt 0.278641 0.482666 +vt 0.283002 0.466748 +vt 0.286849 0.466197 +vt 0.283064 0.465472 +vt 0.286849 0.466197 +vt 0.283002 0.466748 +vt 0.281092 0.495183 +vt 0.280415 0.493664 +vt 0.280080 0.469047 +vt 0.277387 0.497109 +vt 0.280415 0.493664 +vt 0.281092 0.495183 +vt 0.276788 0.496195 +vt 0.280415 0.493664 +vt 0.274920 0.499360 +vt 0.274393 0.498506 +vt 0.273191 0.502580 +vt 0.272812 0.502454 +vt 0.272465 0.506306 +vt 0.272036 0.506416 +vt 0.272102 0.513377 +vt 0.271052 0.505787 +vt 0.270002 0.506414 +vt 0.270475 0.498781 +vt 0.269457 0.497084 +vt 0.272162 0.493546 +vt 0.269979 0.492152 +vt 0.271249 0.490876 +vt 0.271033 0.489938 +vt 0.271164 0.481291 +vt 0.277387 0.497109 +vt 0.276788 0.496195 +vt 0.277387 0.497109 +vt 0.279559 0.488823 +vt 0.276788 0.496195 +vt 0.275946 0.492591 +vt 0.276788 0.496195 +vt 0.279559 0.488823 +vt 0.278641 0.482666 +vt 0.279559 0.488823 +vt 0.274952 0.487792 +vt 0.278641 0.482666 +vt 0.273721 0.481453 +vt 0.278641 0.482666 +vt 0.272162 0.493546 +vt 0.271387 0.482093 +vt 0.272162 0.493546 +vt 0.271249 0.490876 +vt 0.272162 0.493546 +vt 0.271164 0.481291 +vt 0.271249 0.490876 +vt 0.271033 0.489938 +vt 0.271249 0.490876 +vt 0.271164 0.481291 +vt 0.274393 0.498506 +vt 0.273191 0.502580 +vt 0.274920 0.499360 +vt 0.272812 0.502454 +vt 0.273191 0.502580 +vt 0.274393 0.498506 +vt 0.273331 0.496082 +vt 0.272812 0.502454 +vt 0.274393 0.498506 +vt 0.271502 0.500412 +vt 0.272812 0.502454 +vt 0.272162 0.493546 +vt 0.270475 0.498781 +vt 0.272162 0.493546 +vt 0.269457 0.497084 +vt 0.270475 0.498781 +vt 0.272162 0.493546 +vt 0.270002 0.506414 +vt 0.270475 0.498781 +vt 0.269457 0.497084 +vt 0.268906 0.503379 +vt 0.270002 0.506414 +vt 0.269457 0.497084 +vt 0.269600 0.507165 +vt 0.270002 0.506414 +vt 0.268710 0.502888 +vt 0.269797 0.508146 +vt 0.269795 0.491412 +vt 0.268631 0.496066 +vt 0.268906 0.503379 +vt 0.268906 0.503379 +vt 0.269600 0.507165 +vt 0.268906 0.503379 +vt 0.269600 0.507165 +vt 0.269797 0.508146 +vt 0.269600 0.507165 +vt 0.280415 0.493664 +vt 0.275946 0.492591 +vt 0.275946 0.492591 +vt 0.273331 0.496082 +vt 0.275946 0.492591 +vt 0.273331 0.496082 +vt 0.271502 0.500412 +vt 0.273331 0.496082 +vt 0.271502 0.500412 +vt 0.271502 0.500412 +vt 0.273331 0.496082 +vt 0.271502 0.500412 +vt 0.274952 0.487792 +vt 0.273331 0.496082 +vt 0.273721 0.481453 +vt 0.274952 0.487792 +vt 0.274952 0.487792 +vt 0.273721 0.481453 +vt 0.275928 0.474636 +vt 0.273721 0.481453 +vt 0.278259 0.477544 +vt 0.278318 0.475533 +vt 0.278259 0.477544 +vt 0.276478 0.472835 +vt 0.278318 0.475533 +vt 0.273026 0.476508 +vt 0.273721 0.481453 +vt 0.271387 0.482093 +vt 0.273721 0.481453 +vt 0.271387 0.482093 +vt 0.273721 0.481453 +vt 0.271387 0.482093 +vt 0.276788 0.496195 +vt 0.274920 0.499360 +vt 0.277387 0.497109 +vt 0.274393 0.498506 +vt 0.274920 0.499360 +vt 0.276788 0.496195 +vt 0.274393 0.498506 +vt 0.276788 0.496195 +vt 0.274393 0.498506 +vt 0.272162 0.493546 +vt 0.268535 0.495406 +vt 0.268631 0.496066 +vt 0.269457 0.497084 +vt 0.268631 0.496066 +vt 0.269979 0.492152 +vt 0.268631 0.496066 +vt 0.269457 0.497084 +vt 0.272162 0.493546 +vt 0.269979 0.492152 +vt 0.269457 0.497084 +vt 0.271249 0.490876 +vt 0.269979 0.492152 +vt 0.272162 0.493546 +vt 0.273086 0.474679 +vt 0.271164 0.481291 +vt 0.273026 0.476508 +vt 0.273026 0.476508 +vt 0.275928 0.474636 +vt 0.273026 0.476508 +vt 0.278641 0.482666 +vt 0.275928 0.474636 +vt 0.275928 0.474636 +vt 0.278641 0.482666 +vt 0.273086 0.474679 +vt 0.273086 0.474679 +vt 0.268535 0.495406 +vt 0.268535 0.495406 +vt 0.268535 0.495406 +vt 0.271033 0.489938 +vt 0.269795 0.491412 +vt 0.274920 0.499360 +vt 0.271033 0.489938 +vt 0.274920 0.499360 +vt 0.271033 0.489938 +vt 0.277387 0.497109 +vt 0.274920 0.499360 +vt 0.277387 0.497109 +vt 0.268710 0.502888 +vt 0.269600 0.507165 +vt 0.269797 0.508146 +vt 0.268906 0.503379 +vt 0.269600 0.507165 +vt 0.268710 0.502888 +vt 0.268535 0.495406 +vt 0.268906 0.503379 +vt 0.268710 0.502888 +vt 0.268906 0.503379 +vt 0.268535 0.495406 +vt 0.268535 0.495406 +vt 0.272102 0.513377 +vt 0.270002 0.506414 +vt 0.272102 0.513377 +vt 0.271052 0.505787 +vt 0.270002 0.506414 +vt 0.272102 0.513377 +vt 0.270475 0.498781 +vt 0.270002 0.506414 +vt 0.271052 0.505787 +vt 0.270475 0.498781 +vt 0.271052 0.505787 +vt 0.272812 0.502454 +vt 0.272465 0.506306 +vt 0.273191 0.502580 +vt 0.272036 0.506416 +vt 0.272465 0.506306 +vt 0.272812 0.502454 +vt 0.272036 0.506416 +vt 0.272812 0.502454 +vt 0.271052 0.505787 +vt 0.272036 0.506416 +vt 0.273086 0.474679 +vt 0.278318 0.475533 +vt 0.281092 0.495183 +vt 0.278318 0.475533 +vt 0.273086 0.474679 +vt 0.281092 0.495183 +vt 0.273086 0.474679 +vt 0.269797 0.508146 +vt 0.268535 0.495406 +vt 0.268710 0.502888 +vt 0.268535 0.495406 +vt 0.269797 0.508146 +vt 0.269797 0.508146 +vt 0.272465 0.506306 +vt 0.272102 0.513377 +vt 0.272465 0.506306 +vt 0.275946 0.492591 +vt 0.274952 0.487792 +vt 0.275946 0.492591 +vt 0.273331 0.496082 +vt 0.274952 0.487792 +vt 0.275946 0.492591 +vt 0.276478 0.472835 +vt 0.273191 0.502580 +vt 0.272465 0.506306 +vt 0.274920 0.499360 +vt 0.273191 0.502580 +vt 0.271502 0.500412 +vt 0.271502 0.500412 +vt 0.271387 0.482093 +vt 0.273086 0.474679 +vt 0.271387 0.482093 +vt 0.273086 0.474679 +vt 0.271387 0.482093 +vt 0.273086 0.474679 +vt 0.272102 0.513377 +vt 0.272036 0.506416 +vt 0.271052 0.505787 +vt 0.272465 0.506306 +vt 0.272036 0.506416 +vt 0.272102 0.513377 +vt 0.268631 0.496066 +vt 0.269795 0.491412 +vt 0.269979 0.492152 +vt 0.269795 0.491412 +vt 0.268631 0.496066 +vt 0.271033 0.489938 +vt 0.269979 0.492152 +vt 0.271249 0.490876 +vt 0.269795 0.491412 +vt 0.269979 0.492152 +vt 0.271033 0.489938 +vt 0.273026 0.476508 +vt 0.276478 0.472835 +vt 0.275928 0.474636 +vt 0.276478 0.472835 +vt 0.273026 0.476508 +vt 0.275928 0.474636 +vt 0.276478 0.472835 +vt 0.275928 0.474636 +vt 0.268535 0.495406 +vt 0.271033 0.489938 +vt 0.271164 0.481291 +vt 0.273086 0.474679 +vt 0.059691 0.138615 +vt 0.053921 0.137475 +vt 0.054308 0.090538 +vt 0.053720 0.177444 +vt 0.059348 0.180754 +vt 0.054158 0.210338 +vt 0.059938 0.217159 +vt 0.054463 0.231822 +vt 0.060688 0.234699 +vt 0.055024 0.242940 +vt 0.061665 0.249348 +vt 0.055136 0.244957 +vt 0.061888 0.256672 +vt 0.054907 0.239969 +vt 0.061990 0.243977 +vt 0.054229 0.223532 +vt 0.060037 0.227864 +vt 0.053841 0.199973 +vt 0.059974 0.205738 +vt 0.053403 0.168747 +vt 0.059460 0.169929 +vt 0.053635 0.129748 +vt 0.059850 0.128728 +vt 0.054307 0.090228 +vt 0.057921 0.047387 +vt 0.053895 0.052037 +vt 0.053848 0.033454 +vt 0.049137 0.137169 +vt 0.049260 0.177809 +vt 0.049691 0.210037 +vt 0.049749 0.231147 +vt 0.049802 0.241917 +vt 0.049941 0.243814 +vt 0.049825 0.238619 +vt 0.049513 0.222247 +vt 0.049375 0.199741 +vt 0.048946 0.169809 +vt 0.048849 0.129636 +vt 0.079433 0.055047 +vt 0.078656 0.024934 +vt 0.071207 0.046515 +vt 0.083294 0.059036 +vt 0.086058 0.087261 +vt 0.087916 0.117969 +vt 0.088451 0.147781 +vt 0.088719 0.121020 +vt 0.089424 0.150230 +vt 0.087804 0.117924 +vt 0.088291 0.147629 +vt 0.085895 0.087613 +vt 0.083166 0.136622 +vt 0.074816 0.088583 +vt 0.075846 0.134904 +vt 0.067578 0.135677 +vt 0.069527 0.177914 +vt 0.059953 0.089609 +vt 0.066825 0.090062 +vt 0.063800 0.044429 +vt 0.070820 0.046758 +vt 0.070617 0.021809 +vt 0.078525 0.025020 +vt 0.070942 0.008625 +vt 0.070617 0.021809 +vt 0.070617 0.021809 +vt 0.063781 0.020344 +vt 0.070617 0.021809 +vt 0.064270 0.044173 +vt 0.057921 0.031574 +vt 0.054340 0.024250 +vt 0.058247 0.021809 +vt 0.058684 0.009124 +vt 0.064299 0.006672 +vt 0.058247 0.021809 +vt 0.063781 0.020344 +vt 0.058247 0.021809 +vt 0.057921 0.031574 +vt 0.058247 0.021809 +vt 0.063781 0.020344 +vt 0.057921 0.031574 +vt 0.063781 0.020344 +vt 0.057570 0.047646 +vt 0.057921 0.031574 +vt 0.048905 0.034793 +vt 0.053851 0.034853 +vt 0.048949 0.052025 +vt 0.054340 0.024250 +vt 0.048848 0.021746 +vt 0.054340 0.024250 +vt 0.054431 0.017439 +vt 0.054340 0.024250 +vt 0.048896 0.017419 +vt 0.048949 0.021684 +vt 0.048902 0.033389 +vt 0.048949 0.051942 +vt 0.083520 0.136109 +vt 0.084777 0.170735 +vt 0.087544 0.177571 +vt 0.081359 0.204426 +vt 0.082894 0.222448 +vt 0.073221 0.244465 +vt 0.074197 0.252278 +vt 0.005388 0.126420 +vt 0.038687 0.085185 +vt 0.007636 0.085526 +vt 0.043559 0.126408 +vt 0.003000 0.171271 +vt 0.044667 0.170734 +vt 0.005345 0.206974 +vt 0.043468 0.203905 +vt 0.011098 0.230269 +vt 0.038791 0.228772 +vt 0.017687 0.246803 +vt 0.053895 0.052197 +vt 0.057921 0.031574 +vt 0.057921 0.031574 +vt 0.058247 0.021809 +vt 0.057921 0.031574 +vt 0.054340 0.024250 +vt 0.058247 0.021809 +vt 0.058247 0.021809 +vt 0.054340 0.024250 +vt 0.054340 0.024250 +vt 0.073221 0.244465 +vt 0.071105 0.226887 +vt 0.073221 0.244465 +vt 0.082733 0.222118 +vt 0.073221 0.244465 +vt 0.081196 0.204914 +vt 0.087544 0.177571 +vt 0.084777 0.170735 +vt 0.087544 0.177571 +vt 0.087544 0.177571 +vt 0.084777 0.170735 +vt 0.084777 0.170735 +vt 0.036847 0.040800 +vt 0.008085 0.082654 +vt 0.037775 0.082224 +vt 0.008112 0.040891 +vt 0.033251 0.020328 +vt 0.010412 0.021878 +vt 0.027992 0.007444 +vt 0.015576 0.007471 +vt 0.076401 0.133980 +vt 0.078530 0.170748 +vt 0.068194 0.134714 +vt 0.070120 0.176544 +vt 0.063781 0.020344 +vt 0.063781 0.020344 +vt 0.063781 0.020344 +vt 0.070617 0.021809 +vt 0.070617 0.021809 +vt 0.071105 0.226887 +vt 0.071105 0.226887 +vt 0.071105 0.226887 +vt 0.079124 0.055245 +vt 0.078018 0.172063 +vt 0.089985 0.182942 +vt 0.087381 0.238117 +vt 0.049045 0.089873 +vt 0.071105 0.226887 +vt 0.071105 0.226887 +vt 0.087544 0.177571 +vt 0.084777 0.170735 +vt 0.084777 0.170735 +vt 0.071105 0.226887 +vt 0.071105 0.226887 +vt 0.049044 0.089484 +vt 0.032394 0.246947 +vt 0.025072 0.252721 +vt 0.087544 0.177571 +vt 0.073221 0.244465 +vt 0.073221 0.244465 +vt 0.049919 0.102775 +vt 0.049132 0.138312 +vt 0.049924 0.177272 +vt 0.009944 0.556824 +vt 0.009944 0.608689 +vt 0.002959 0.608255 +vt 0.021163 0.559239 +vt 0.021163 0.519200 +vt 0.036313 0.524614 +vt 0.036806 0.488919 +vt 0.059410 0.490474 +vt 0.037053 0.455697 +vt 0.059410 0.458526 +vt 0.059410 0.419553 +vt 0.077221 0.419184 +vt 0.077221 0.379418 +vt 0.084130 0.378994 +vt 0.077221 0.351197 +vt 0.084031 0.351127 +vt 0.084130 0.378994 +vt 0.092572 0.380161 +vt 0.084130 0.378994 +vt 0.083907 0.418673 +vt 0.084130 0.378994 +vt 0.091710 0.418214 +vt 0.083654 0.457483 +vt 0.091209 0.457207 +vt 0.091123 0.489017 +vt 0.100499 0.489017 +vt 0.092089 0.520692 +vt 0.101233 0.519536 +vt 0.092680 0.564063 +vt 0.101731 0.558973 +vt 0.093055 0.625218 +vt 0.103061 0.625564 +vt 0.092603 0.673187 +vt 0.103917 0.681925 +vt 0.092856 0.722900 +vt 0.105363 0.731159 +vt 0.098125 0.782050 +vt 0.109069 0.776116 +vt 0.102996 0.834417 +vt 0.114078 0.812041 +vt 0.109069 0.776116 +vt 0.122379 0.752794 +vt 0.109069 0.776116 +vt 0.105363 0.731159 +vt 0.109069 0.776116 +vt 0.115842 0.664357 +vt 0.105363 0.731159 +vt 0.103917 0.681925 +vt 0.105363 0.731159 +vt 0.103061 0.625564 +vt 0.103917 0.681925 +vt 0.092603 0.673187 +vt 0.103061 0.625564 +vt 0.103917 0.681925 +vt 0.093055 0.625218 +vt 0.103061 0.625564 +vt 0.092603 0.673187 +vt 0.084543 0.667439 +vt 0.093055 0.625218 +vt 0.092603 0.673187 +vt 0.084500 0.620825 +vt 0.093055 0.625218 +vt 0.077221 0.663145 +vt 0.077221 0.616875 +vt 0.059410 0.659118 +vt 0.059410 0.615692 +vt 0.033348 0.652294 +vt 0.033348 0.609484 +vt 0.019970 0.645796 +vt 0.021163 0.600589 +vt 0.009944 0.634867 +vt 0.035324 0.566463 +vt 0.059410 0.527025 +vt 0.077221 0.489964 +vt 0.077221 0.458318 +vt 0.083907 0.418673 +vt 0.083907 0.418673 +vt 0.092572 0.380161 +vt 0.083907 0.418673 +vt 0.092572 0.380161 +vt 0.093538 0.352466 +vt 0.092572 0.380161 +vt 0.105981 0.388027 +vt 0.102000 0.424667 +vt 0.100443 0.458068 +vt 0.114882 0.489017 +vt 0.113413 0.554053 +vt 0.009944 0.510901 +vt 0.021162 0.484610 +vt 0.009944 0.451162 +vt 0.021162 0.451248 +vt 0.021162 0.413581 +vt 0.037053 0.416849 +vt 0.037053 0.379418 +vt 0.059410 0.379418 +vt 0.037053 0.351197 +vt 0.059410 0.351197 +vt 0.059410 0.379418 +vt 0.077221 0.379418 +vt 0.059410 0.379418 +vt 0.059410 0.419553 +vt 0.077221 0.379418 +vt 0.059410 0.379418 +vt 0.077221 0.419184 +vt 0.077221 0.379418 +vt 0.059410 0.419553 +vt 0.059410 0.458526 +vt 0.077221 0.419184 +vt 0.059410 0.419553 +vt 0.077221 0.458318 +vt 0.077221 0.419184 +vt 0.059410 0.458526 +vt 0.077221 0.489964 +vt 0.077221 0.458318 +vt 0.059410 0.458526 +vt 0.083654 0.489900 +vt 0.077221 0.458318 +vt 0.077221 0.489964 +vt 0.077221 0.526506 +vt 0.077221 0.489964 +vt 0.083581 0.523331 +vt 0.077221 0.571088 +vt 0.084031 0.568553 +vt 0.059410 0.570472 +vt 0.077221 0.526506 +vt 0.077221 0.526506 +vt 0.083654 0.489900 +vt 0.077221 0.526506 +vt 0.083654 0.489900 +vt 0.083654 0.457483 +vt 0.083654 0.489900 +vt 0.083907 0.418673 +vt 0.083654 0.457483 +vt 0.091710 0.418214 +vt 0.083654 0.457483 +vt 0.083907 0.418673 +vt 0.092572 0.380161 +vt 0.091710 0.418214 +vt 0.083907 0.418673 +vt 0.105981 0.388027 +vt 0.091710 0.418214 +vt 0.092572 0.380161 +vt 0.105981 0.388027 +vt 0.092572 0.380161 +vt 0.109593 0.367061 +vt 0.105981 0.388027 +vt 0.118719 0.414380 +vt 0.115324 0.437940 +vt 0.077221 0.571088 +vt 0.077221 0.526506 +vt 0.077221 0.571088 +vt 0.083581 0.523331 +vt 0.077221 0.571088 +vt 0.077221 0.526506 +vt 0.083654 0.489900 +vt 0.083581 0.523331 +vt 0.077221 0.526506 +vt 0.091123 0.489017 +vt 0.083581 0.523331 +vt 0.083654 0.489900 +vt 0.083654 0.457483 +vt 0.091123 0.489017 +vt 0.083654 0.489900 +vt 0.091209 0.457207 +vt 0.091123 0.489017 +vt 0.083654 0.457483 +vt 0.091710 0.418214 +vt 0.091209 0.457207 +vt 0.083654 0.457483 +vt 0.102000 0.424667 +vt 0.091209 0.457207 +vt 0.091710 0.418214 +vt 0.105981 0.388027 +vt 0.102000 0.424667 +vt 0.091710 0.418214 +vt 0.118719 0.414380 +vt 0.102000 0.424667 +vt 0.105981 0.388027 +vt 0.118719 0.414380 +vt 0.105981 0.388027 +vt 0.122057 0.398171 +vt 0.118719 0.414380 +vt 0.129175 0.441739 +vt 0.125662 0.455993 +vt 0.124739 0.489017 +vt 0.140301 0.489017 +vt 0.009944 0.378879 +vt 0.021162 0.379418 +vt 0.009944 0.351197 +vt 0.021162 0.351197 +vt 0.021162 0.379418 +vt 0.037053 0.379418 +vt 0.021162 0.379418 +vt 0.021162 0.413581 +vt 0.037053 0.379418 +vt 0.021162 0.379418 +vt 0.037053 0.416849 +vt 0.037053 0.379418 +vt 0.021162 0.413581 +vt 0.021162 0.451248 +vt 0.037053 0.416849 +vt 0.021162 0.413581 +vt 0.037053 0.455697 +vt 0.037053 0.416849 +vt 0.021162 0.451248 +vt 0.036806 0.488919 +vt 0.037053 0.455697 +vt 0.021162 0.451248 +vt 0.059410 0.490474 +vt 0.037053 0.455697 +vt 0.036806 0.488919 +vt 0.036313 0.524614 +vt 0.059410 0.490474 +vt 0.036806 0.488919 +vt 0.059410 0.527025 +vt 0.059410 0.490474 +vt 0.036313 0.524614 +vt 0.035324 0.566463 +vt 0.059410 0.527025 +vt 0.036313 0.524614 +vt 0.059410 0.570472 +vt 0.059410 0.527025 +vt 0.035324 0.566463 +vt 0.009944 0.608689 +vt 0.009944 0.556824 +vt 0.002959 0.608255 +vt 0.021163 0.559239 +vt 0.009944 0.556824 +vt 0.009944 0.608689 +vt 0.021163 0.600589 +vt 0.021163 0.559239 +vt 0.009944 0.608689 +vt 0.035324 0.566463 +vt 0.021163 0.559239 +vt 0.021163 0.600589 +vt 0.033348 0.609484 +vt 0.035324 0.566463 +vt 0.021163 0.600589 +vt 0.059410 0.570472 +vt 0.035324 0.566463 +vt 0.033348 0.609484 +vt 0.059410 0.615692 +vt 0.059410 0.570472 +vt 0.033348 0.609484 +vt 0.059410 0.570472 +vt 0.059410 0.615692 +vt 0.077221 0.616875 +vt 0.059410 0.615692 +vt 0.077221 0.616875 +vt 0.084500 0.620825 +vt 0.077221 0.616875 +vt 0.084500 0.620825 +vt 0.084500 0.620825 +vt 0.077221 0.571088 +vt 0.084031 0.568553 +vt 0.077221 0.571088 +vt 0.083581 0.523331 +vt 0.084031 0.568553 +vt 0.077221 0.571088 +vt 0.092089 0.520692 +vt 0.084031 0.568553 +vt 0.083581 0.523331 +vt 0.091123 0.489017 +vt 0.092089 0.520692 +vt 0.083581 0.523331 +vt 0.100499 0.489017 +vt 0.092089 0.520692 +vt 0.091123 0.489017 +vt 0.091209 0.457207 +vt 0.100499 0.489017 +vt 0.091123 0.489017 +vt 0.100443 0.458068 +vt 0.100499 0.489017 +vt 0.091209 0.457207 +vt 0.102000 0.424667 +vt 0.100443 0.458068 +vt 0.091209 0.457207 +vt 0.115324 0.437940 +vt 0.100443 0.458068 +vt 0.102000 0.424667 +vt 0.118719 0.414380 +vt 0.115324 0.437940 +vt 0.102000 0.424667 +vt 0.129175 0.441739 +vt 0.115324 0.437940 +vt 0.118719 0.414380 +vt 0.092680 0.564063 +vt 0.093055 0.625218 +vt 0.101731 0.558973 +vt 0.093055 0.625218 +vt 0.092680 0.564063 +vt 0.101233 0.519536 +vt 0.101731 0.558973 +vt 0.092680 0.564063 +vt 0.113413 0.554053 +vt 0.101731 0.558973 +vt 0.101233 0.519536 +vt 0.114882 0.489017 +vt 0.113413 0.554053 +vt 0.101233 0.519536 +vt 0.124739 0.489017 +vt 0.113413 0.554053 +vt 0.114882 0.489017 +vt 0.115324 0.437940 +vt 0.124739 0.489017 +vt 0.114882 0.489017 +vt 0.125662 0.455993 +vt 0.124739 0.489017 +vt 0.115324 0.437940 +vt 0.129175 0.441739 +vt 0.125662 0.455993 +vt 0.115324 0.437940 +vt 0.125662 0.455993 +vt 0.129175 0.441739 +vt 0.009944 0.378879 +vt 0.021162 0.379418 +vt 0.021162 0.413581 +vt 0.021162 0.379418 +vt 0.009944 0.378879 +vt 0.009944 0.451162 +vt 0.021162 0.413581 +vt 0.009944 0.378879 +vt 0.021162 0.451248 +vt 0.021162 0.413581 +vt 0.009944 0.451162 +vt 0.021162 0.484610 +vt 0.021162 0.451248 +vt 0.009944 0.451162 +vt 0.036806 0.488919 +vt 0.021162 0.451248 +vt 0.021162 0.484610 +vt 0.021163 0.519200 +vt 0.036806 0.488919 +vt 0.021162 0.484610 +vt 0.036313 0.524614 +vt 0.036806 0.488919 +vt 0.021163 0.519200 +vt 0.021163 0.559239 +vt 0.036313 0.524614 +vt 0.021163 0.519200 +vt 0.035324 0.566463 +vt 0.036313 0.524614 +vt 0.021163 0.559239 +vt 0.007721 0.918650 +vt 0.004111 0.976813 +vt 0.007721 0.976813 +vt 0.004111 0.918650 +vt 0.007721 0.867819 +vt 0.004111 0.867819 +vt 0.007721 0.823496 +vt 0.004111 0.823496 +vt 0.007721 0.778760 +vt 0.004111 0.778760 +vt 0.007721 0.743992 +vt 0.004111 0.743992 +vt 0.015318 0.644506 +vt 0.016590 0.623082 +vt 0.012959 0.618304 +vt 0.022929 0.638619 +vt 0.018652 0.667650 +vt 0.028136 0.660392 +vt 0.020361 0.703132 +vt 0.033664 0.693453 +vt 0.020798 0.735268 +vt 0.038200 0.735268 +vt 0.033664 0.693453 +vt 0.059410 0.570472 +vt 0.059410 0.527025 +vt 0.059410 0.570472 +vt 0.077221 0.489964 +vt 0.059410 0.527025 +vt 0.059410 0.490474 +vt 0.059410 0.527025 +vt 0.077221 0.489964 +vt 0.059410 0.458526 +vt 0.059410 0.490474 +vt 0.077221 0.489964 +vt 0.037053 0.455697 +vt 0.059410 0.490474 +vt 0.059410 0.458526 +vt 0.059410 0.419553 +vt 0.037053 0.455697 +vt 0.059410 0.458526 +vt 0.037053 0.416849 +vt 0.037053 0.455697 +vt 0.059410 0.419553 +vt 0.059410 0.379418 +vt 0.037053 0.416849 +vt 0.059410 0.419553 +vt 0.059216 0.973897 +vt 0.080281 0.861287 +vt 0.077006 0.947718 +vt 0.062336 0.861316 +vt 0.035705 0.861316 +vt 0.059216 0.749919 +vt 0.033077 0.742518 +vt 0.059410 0.701245 +vt 0.033348 0.693633 +vt 0.084031 0.568553 +vt 0.092680 0.564063 +vt 0.084031 0.568553 +vt 0.092089 0.520692 +vt 0.092680 0.564063 +vt 0.084031 0.568553 +vt 0.101233 0.519536 +vt 0.092680 0.564063 +vt 0.092089 0.520692 +vt 0.100499 0.489017 +vt 0.101233 0.519536 +vt 0.092089 0.520692 +vt 0.114882 0.489017 +vt 0.101233 0.519536 +vt 0.100499 0.489017 +vt 0.100443 0.458068 +vt 0.114882 0.489017 +vt 0.100499 0.489017 +vt 0.115324 0.437940 +vt 0.114882 0.489017 +vt 0.100443 0.458068 +vt 0.129397 0.761799 +vt 0.122379 0.752794 +vt 0.128861 0.668134 +vt 0.122379 0.752794 +vt 0.125140 0.619516 +vt 0.122379 0.752794 +vt 0.126351 0.538577 +vt 0.033077 0.742401 +vt 0.018031 0.693981 +vt 0.014248 0.746356 +vt 0.033348 0.693633 +vt 0.059410 0.701245 +vt 0.033348 0.693633 +vt 0.059410 0.659118 +vt 0.033348 0.693633 +vt 0.059410 0.701245 +vt 0.077221 0.663145 +vt 0.059410 0.659118 +vt 0.059410 0.701245 +vt 0.077221 0.616875 +vt 0.059410 0.659118 +vt 0.077221 0.663145 +vt 0.084500 0.620825 +vt 0.077221 0.616875 +vt 0.077221 0.663145 +vt 0.059216 0.749801 +vt 0.059410 0.701245 +vt 0.077221 0.709272 +vt 0.059410 0.701245 +vt 0.077006 0.774738 +vt 0.085187 0.714896 +vt 0.087806 0.781243 +vt 0.092660 0.853724 +vt 0.087806 0.781243 +vt 0.098125 0.782050 +vt 0.087806 0.781243 +vt 0.092856 0.722900 +vt 0.098125 0.782050 +vt 0.087806 0.781243 +vt 0.105363 0.731159 +vt 0.098125 0.782050 +vt 0.092856 0.722900 +vt 0.103917 0.681925 +vt 0.105363 0.731159 +vt 0.092856 0.722900 +vt 0.129442 0.903002 +vt 0.107555 0.898819 +vt 0.135450 0.883505 +vt 0.101120 0.933314 +vt 0.125991 0.933003 +vt 0.098671 0.973635 +vt 0.123581 0.973635 +vt 0.125991 0.933003 +vt 0.009944 0.634867 +vt 0.021163 0.600589 +vt 0.009944 0.608689 +vt 0.019970 0.645796 +vt 0.021163 0.600589 +vt 0.009944 0.634867 +vt 0.019970 0.645796 +vt 0.009944 0.634867 +vt 0.033348 0.652294 +vt 0.019970 0.645796 +vt 0.033348 0.693633 +vt 0.033348 0.652294 +vt 0.059410 0.659118 +vt 0.033348 0.652294 +vt 0.033348 0.693633 +vt 0.077006 0.774767 +vt 0.077221 0.709272 +vt 0.085187 0.714896 +vt 0.077221 0.709272 +vt 0.085187 0.714896 +vt 0.077221 0.709272 +vt 0.092603 0.673187 +vt 0.085187 0.714896 +vt 0.131386 0.434007 +vt 0.129175 0.441739 +vt 0.129175 0.441739 +vt 0.118719 0.414380 +vt 0.129175 0.441739 +vt 0.059410 0.615692 +vt 0.059410 0.659118 +vt 0.077221 0.616875 +vt 0.033348 0.652294 +vt 0.059410 0.659118 +vt 0.059410 0.615692 +vt 0.033348 0.609484 +vt 0.033348 0.652294 +vt 0.059410 0.615692 +vt 0.019970 0.645796 +vt 0.033348 0.652294 +vt 0.033348 0.609484 +vt 0.021163 0.600589 +vt 0.019970 0.645796 +vt 0.033348 0.609484 +vt 0.098125 0.782050 +vt 0.109069 0.776116 +vt 0.098125 0.782050 +vt 0.105363 0.731159 +vt 0.109069 0.776116 +vt 0.098125 0.782050 +vt 0.122379 0.752794 +vt 0.122379 0.752794 +vt 0.115842 0.664357 +vt 0.122379 0.752794 +vt 0.115842 0.664357 +vt 0.115842 0.664357 +vt 0.125140 0.619516 +vt 0.126351 0.538577 +vt 0.128861 0.668134 +vt 0.125140 0.619516 +vt 0.132554 0.671435 +vt 0.128861 0.668134 +vt 0.128861 0.668134 +vt 0.162542 0.642582 +vt 0.141988 0.705957 +vt 0.138988 0.693980 +vt 0.162542 0.723048 +vt 0.141988 0.705957 +vt 0.147523 0.722907 +vt 0.141988 0.705957 +vt 0.125140 0.619516 +vt 0.126351 0.538577 +vt 0.125140 0.619516 +vt 0.128861 0.668134 +vt 0.125140 0.619516 +vt 0.128861 0.668134 +vt 0.009944 0.510901 +vt 0.021162 0.484610 +vt 0.009944 0.451162 +vt 0.021163 0.519200 +vt 0.021162 0.484610 +vt 0.009944 0.510901 +vt 0.009944 0.556824 +vt 0.021163 0.519200 +vt 0.009944 0.510901 +vt 0.021163 0.559239 +vt 0.021163 0.519200 +vt 0.009944 0.556824 +vt 0.084543 0.667439 +vt 0.084543 0.667439 +vt 0.084500 0.620825 +vt 0.084543 0.667439 +vt 0.113413 0.554053 +vt 0.103061 0.625564 +vt 0.126351 0.538577 +vt 0.113413 0.554053 +vt 0.124739 0.489017 +vt 0.126351 0.538577 +vt 0.113413 0.554053 +vt 0.126351 0.538577 +vt 0.124739 0.489017 +vt 0.077221 0.663145 +vt 0.084543 0.667439 +vt 0.084500 0.620825 +vt 0.084543 0.667439 +vt 0.077221 0.663145 +vt 0.059410 0.701245 +vt 0.077221 0.663145 +vt 0.135450 0.883505 +vt 0.118765 0.871711 +vt 0.107555 0.898819 +vt 0.132360 0.859792 +vt 0.135450 0.883505 +vt 0.138451 0.861963 +vt 0.135450 0.883505 +vt 0.132360 0.859792 +vt 0.138451 0.861963 +vt 0.118765 0.871711 +vt 0.132360 0.859792 +vt 0.118765 0.871711 +vt 0.138988 0.693980 +vt 0.141988 0.705957 +vt 0.136042 0.658374 +vt 0.138988 0.693980 +vt 0.136765 0.626789 +vt 0.077221 0.709272 +vt 0.077221 0.709272 +vt 0.017594 0.861287 +vt 0.014248 0.746444 +vt 0.014248 0.976041 +vt 0.033077 0.981948 +vt 0.147523 0.722907 +vt 0.156009 0.731665 +vt 0.147523 0.722907 +vt 0.162542 0.733905 +vt 0.115842 0.664357 +vt 0.115842 0.664357 +vt 0.115842 0.664357 +vt 0.020361 0.703132 +vt 0.033664 0.693453 +vt 0.028136 0.660392 +vt 0.033664 0.693453 +vt 0.020361 0.703132 +vt 0.018652 0.667650 +vt 0.028136 0.660392 +vt 0.020361 0.703132 +vt 0.162542 0.590306 +vt 0.143058 0.590306 +vt 0.157397 0.567975 +vt 0.162542 0.567975 +vt 0.007721 0.743992 +vt 0.004111 0.778760 +vt 0.004111 0.743992 +vt 0.007721 0.778760 +vt 0.004111 0.778760 +vt 0.007721 0.743992 +vt 0.018031 0.693981 +vt 0.007721 0.823496 +vt 0.004111 0.867819 +vt 0.004111 0.823496 +vt 0.007721 0.867819 +vt 0.004111 0.867819 +vt 0.007721 0.823496 +vt 0.101731 0.558973 +vt 0.103061 0.625564 +vt 0.093055 0.625218 +vt 0.113413 0.554053 +vt 0.103061 0.625564 +vt 0.101731 0.558973 +vt 0.007721 0.867819 +vt 0.004111 0.918650 +vt 0.004111 0.867819 +vt 0.007721 0.918650 +vt 0.004111 0.918650 +vt 0.007721 0.867819 +vt 0.007721 0.918650 +vt 0.004111 0.918650 +vt 0.007721 0.918650 +vt 0.037053 0.379418 +vt 0.059410 0.379418 +vt 0.037053 0.416849 +vt 0.059410 0.379418 +vt 0.037053 0.379418 +vt 0.077221 0.379418 +vt 0.037053 0.379418 +vt 0.022929 0.638619 +vt 0.018652 0.667650 +vt 0.015318 0.644506 +vt 0.028136 0.660392 +vt 0.018652 0.667650 +vt 0.022929 0.638619 +vt 0.085187 0.714896 +vt 0.092856 0.722900 +vt 0.087806 0.781243 +vt 0.092603 0.673187 +vt 0.092856 0.722900 +vt 0.085187 0.714896 +vt 0.125991 0.933003 +vt 0.101120 0.933314 +vt 0.129442 0.903002 +vt 0.101120 0.933314 +vt 0.125991 0.933003 +vt 0.129442 0.903002 +vt 0.107555 0.898819 +vt 0.101120 0.933314 +vt 0.135450 0.883505 +vt 0.107555 0.898819 +vt 0.129442 0.903002 +vt 0.077221 0.379418 +vt 0.084130 0.378994 +vt 0.077221 0.419184 +vt 0.084130 0.378994 +vt 0.077221 0.379418 +vt 0.077221 0.419184 +vt 0.084130 0.378994 +vt 0.077221 0.458318 +vt 0.077221 0.419184 +vt 0.136042 0.658374 +vt 0.136765 0.626789 +vt 0.136042 0.658374 +vt 0.077221 0.458318 +vt 0.077221 0.458318 +vt 0.156009 0.731665 +vt 0.156009 0.731665 +vt 0.087806 0.781243 +vt 0.085187 0.714896 +vt 0.087806 0.781243 +vt 0.136765 0.626789 +vt 0.143058 0.590306 +vt 0.136765 0.626789 +vt 0.157397 0.567975 +vt 0.143058 0.590306 +vt 0.007721 0.778760 +vt 0.004111 0.823496 +vt 0.004111 0.778760 +vt 0.007721 0.823496 +vt 0.004111 0.823496 +vt 0.007721 0.778760 +vt 0.018031 0.693981 +vt 0.018031 0.693981 +vt 0.016590 0.623082 +vt 0.015318 0.644506 +vt 0.012959 0.618304 +vt 0.022929 0.638619 +vt 0.015318 0.644506 +vt 0.016590 0.623082 +vt 0.018031 0.693981 +vt 0.018031 0.693981 +vt 0.124739 0.489017 +vt 0.125662 0.455993 +vt 0.077221 0.709272 +vt 0.092603 0.673187 +vt 0.103917 0.681925 +vt 0.092856 0.722900 +vt 0.084543 0.667439 +vt 0.157397 0.567975 +vt 0.115842 0.664357 +vt 0.122379 0.752794 +vt 0.279042 0.957224 +vt 0.283841 0.956948 +vt 0.279076 0.964797 +vt 0.283007 0.924172 +vt 0.279050 0.921809 +vt 0.285666 0.894376 +vt 0.278964 0.893360 +vt 0.286297 0.886857 +vt 0.279004 0.884609 +vt 0.278803 0.865380 +vt 0.272075 0.865717 +vt 0.278729 0.837282 +vt 0.272839 0.835411 +vt 0.269089 0.802840 +vt 0.267782 0.832417 +vt 0.264323 0.803475 +vt 0.258445 0.802905 +vt 0.259340 0.783451 +vt 0.252445 0.783194 +vt 0.252940 0.771973 +vt 0.246033 0.768224 +vt 0.246568 0.755886 +vt 0.238791 0.763570 +vt 0.238791 0.751783 +vt 0.246568 0.755886 +vt 0.247456 0.749211 +vt 0.246568 0.755886 +vt 0.254338 0.766447 +vt 0.246568 0.755886 +vt 0.255458 0.762273 +vt 0.259173 0.767260 +vt 0.278181 0.766830 +vt 0.280606 0.782817 +vt 0.295621 0.780476 +vt 0.295621 0.805919 +vt 0.298400 0.780476 +vt 0.298400 0.805919 +vt 0.301991 0.780476 +vt 0.301991 0.805888 +vt 0.307262 0.805763 +vt 0.332478 0.871578 +vt 0.326046 0.876066 +vt 0.317729 0.868690 +vt 0.326036 0.880963 +vt 0.332443 0.905196 +vt 0.327460 0.910925 +vt 0.327509 0.942814 +vt 0.324223 0.942631 +vt 0.321231 0.964223 +vt 0.316774 0.955723 +vt 0.315411 0.980287 +vt 0.311938 0.969699 +vt 0.306022 0.981785 +vt 0.305873 0.970206 +vt 0.300491 0.972497 +vt 0.300785 0.962521 +vt 0.294936 0.938752 +vt 0.298115 0.941334 +vt 0.295550 0.920200 +vt 0.298528 0.922487 +vt 0.300537 0.909108 +vt 0.309083 0.929137 +vt 0.309524 0.911124 +vt 0.318157 0.917748 +vt 0.314838 0.901584 +vt 0.318231 0.889863 +vt 0.310881 0.877548 +vt 0.317035 0.868962 +vt 0.305396 0.874424 +vt 0.302847 0.868819 +vt 0.298677 0.879312 +vt 0.246033 0.768224 +vt 0.246568 0.755886 +vt 0.252940 0.771973 +vt 0.246568 0.755886 +vt 0.246033 0.768224 +vt 0.252445 0.783194 +vt 0.252940 0.771973 +vt 0.246033 0.768224 +vt 0.259340 0.783451 +vt 0.252940 0.771973 +vt 0.252445 0.783194 +vt 0.258445 0.802905 +vt 0.259340 0.783451 +vt 0.252445 0.783194 +vt 0.264323 0.803475 +vt 0.259340 0.783451 +vt 0.258445 0.802905 +vt 0.267782 0.832417 +vt 0.264323 0.803475 +vt 0.258445 0.802905 +vt 0.269089 0.802840 +vt 0.264323 0.803475 +vt 0.267782 0.832417 +vt 0.272839 0.835411 +vt 0.269089 0.802840 +vt 0.267782 0.832417 +vt 0.278729 0.837282 +vt 0.269089 0.802840 +vt 0.272839 0.835411 +vt 0.272075 0.865717 +vt 0.278729 0.837282 +vt 0.272839 0.835411 +vt 0.278803 0.865380 +vt 0.278729 0.837282 +vt 0.272075 0.865717 +vt 0.279004 0.884609 +vt 0.278803 0.865380 +vt 0.272075 0.865717 +vt 0.286297 0.886857 +vt 0.278803 0.865380 +vt 0.279004 0.884609 +vt 0.278964 0.893360 +vt 0.286297 0.886857 +vt 0.279004 0.884609 +vt 0.285666 0.894376 +vt 0.286297 0.886857 +vt 0.278964 0.893360 +vt 0.279050 0.921809 +vt 0.285666 0.894376 +vt 0.278964 0.893360 +vt 0.283007 0.924172 +vt 0.285666 0.894376 +vt 0.279050 0.921809 +vt 0.279042 0.957224 +vt 0.283007 0.924172 +vt 0.279050 0.921809 +vt 0.283841 0.956948 +vt 0.283007 0.924172 +vt 0.279042 0.957224 +vt 0.279076 0.964797 +vt 0.283841 0.956948 +vt 0.279042 0.957224 +vt 0.324729 0.732386 +vt 0.326094 0.739571 +vt 0.324715 0.731367 +vt 0.326025 0.740081 +vt 0.323161 0.736013 +vt 0.324092 0.747776 +vt 0.319952 0.747776 +vt 0.320459 0.759629 +vt 0.320459 0.759629 +vt 0.320698 0.772128 +vt 0.320459 0.759629 +vt 0.320698 0.772128 +vt 0.320459 0.759629 +vt 0.320386 0.782080 +vt 0.320698 0.772128 +vt 0.320386 0.782080 +vt 0.320698 0.772128 +vt 0.319666 0.788840 +vt 0.320386 0.782080 +vt 0.319666 0.788840 +vt 0.320386 0.782080 +vt 0.318831 0.792414 +vt 0.319666 0.788840 +vt 0.318831 0.792414 +vt 0.319666 0.788840 +vt 0.317951 0.793867 +vt 0.318831 0.792414 +vt 0.321122 0.792414 +vt 0.318831 0.792414 +vt 0.320964 0.792414 +vt 0.324463 0.788840 +vt 0.271428 0.891517 +vt 0.271627 0.882871 +vt 0.264714 0.888111 +vt 0.265589 0.878377 +vt 0.256093 0.876854 +vt 0.258929 0.870492 +vt 0.252444 0.859975 +vt 0.261320 0.853156 +vt 0.253440 0.842242 +vt 0.254021 0.821827 +vt 0.246837 0.842192 +vt 0.247526 0.807069 +vt 0.242648 0.807233 +vt 0.242253 0.800177 +vt 0.238791 0.805311 +vt 0.238791 0.798041 +vt 0.242253 0.800177 +vt 0.242018 0.799325 +vt 0.242253 0.800177 +vt 0.247791 0.800330 +vt 0.242253 0.800177 +vt 0.318768 0.801005 +vt 0.320964 0.801005 +vt 0.317951 0.799552 +vt 0.321873 0.804579 +vt 0.319469 0.804579 +vt 0.323326 0.811340 +vt 0.320023 0.811340 +vt 0.324249 0.821291 +vt 0.320375 0.821291 +vt 0.320556 0.833790 +vt 0.320375 0.821291 +vt 0.320556 0.833790 +vt 0.320375 0.821291 +vt 0.324249 0.821291 +vt 0.320556 0.833790 +vt 0.320375 0.821291 +vt 0.324546 0.833790 +vt 0.320556 0.833790 +vt 0.324249 0.821291 +vt 0.327052 0.821291 +vt 0.324249 0.821291 +vt 0.327155 0.833790 +vt 0.328368 0.833790 +vt 0.327474 0.845643 +vt 0.323628 0.804579 +vt 0.325726 0.811340 +vt 0.327052 0.821291 +vt 0.327052 0.821291 +vt 0.324546 0.833790 +vt 0.327052 0.821291 +vt 0.324546 0.833790 +vt 0.320306 0.845643 +vt 0.324546 0.833790 +vt 0.320556 0.833790 +vt 0.320306 0.845643 +vt 0.320556 0.833790 +vt 0.320306 0.845643 +vt 0.320556 0.833790 +vt 0.324075 0.845643 +vt 0.320306 0.845643 +vt 0.326308 0.845643 +vt 0.326094 0.853848 +vt 0.301991 0.746944 +vt 0.277337 0.762185 +vt 0.301991 0.750255 +vt 0.269902 0.746944 +vt 0.263000 0.737939 +vt 0.238791 0.741281 +vt 0.269902 0.746944 +vt 0.248297 0.746879 +vt 0.269902 0.746944 +vt 0.277337 0.762185 +vt 0.269902 0.746944 +vt 0.255458 0.762273 +vt 0.277337 0.762185 +vt 0.278181 0.766830 +vt 0.255458 0.762273 +vt 0.277337 0.762185 +vt 0.259173 0.767260 +vt 0.255458 0.762273 +vt 0.278181 0.766830 +vt 0.280606 0.782817 +vt 0.259173 0.767260 +vt 0.278181 0.766830 +vt 0.272204 0.782021 +vt 0.259173 0.767260 +vt 0.280606 0.782817 +vt 0.278077 0.804335 +vt 0.280606 0.782817 +vt 0.263570 0.781849 +vt 0.324463 0.804579 +vt 0.326874 0.811340 +vt 0.328175 0.821291 +vt 0.327052 0.821291 +vt 0.328368 0.833790 +vt 0.327052 0.821291 +vt 0.327155 0.833790 +vt 0.328368 0.833790 +vt 0.327052 0.821291 +vt 0.327474 0.845643 +vt 0.328368 0.833790 +vt 0.327155 0.833790 +vt 0.326308 0.845643 +vt 0.327474 0.845643 +vt 0.327155 0.833790 +vt 0.324859 0.853681 +vt 0.327474 0.845643 +vt 0.326308 0.845643 +vt 0.323089 0.853514 +vt 0.326308 0.845643 +vt 0.322103 0.861385 +vt 0.320169 0.853102 +vt 0.320031 0.860561 +vt 0.317951 0.859608 +vt 0.250047 0.539728 +vt 0.249473 0.540724 +vt 0.247649 0.522977 +vt 0.253473 0.559399 +vt 0.254330 0.556527 +vt 0.258843 0.576968 +vt 0.260012 0.572264 +vt 0.266442 0.585477 +vt 0.267620 0.579829 +vt 0.275704 0.583749 +vt 0.276622 0.578481 +vt 0.285177 0.566397 +vt 0.285461 0.564519 +vt 0.289316 0.540202 +vt 0.284684 0.559677 +vt 0.283947 0.554349 +vt 0.277417 0.559242 +vt 0.326036 0.880963 +vt 0.332443 0.905196 +vt 0.332478 0.871578 +vt 0.327460 0.910925 +vt 0.332443 0.905196 +vt 0.326036 0.880963 +vt 0.318231 0.889863 +vt 0.327460 0.910925 +vt 0.326036 0.880963 +vt 0.323552 0.918475 +vt 0.327460 0.910925 +vt 0.318231 0.889863 +vt 0.318157 0.917748 +vt 0.318231 0.889863 +vt 0.318857 0.938198 +vt 0.318157 0.917748 +vt 0.309083 0.929137 +vt 0.318157 0.917748 +vt 0.316774 0.955723 +vt 0.309083 0.929137 +vt 0.307446 0.946584 +vt 0.316774 0.955723 +vt 0.309083 0.929137 +vt 0.311938 0.969699 +vt 0.316774 0.955723 +vt 0.305873 0.970206 +vt 0.311938 0.969699 +vt 0.306022 0.981785 +vt 0.311938 0.969699 +vt 0.305873 0.970206 +vt 0.300491 0.972497 +vt 0.306022 0.981785 +vt 0.305873 0.970206 +vt 0.299468 0.975881 +vt 0.306022 0.981785 +vt 0.300491 0.972497 +vt 0.294936 0.938752 +vt 0.300491 0.972497 +vt 0.317035 0.868962 +vt 0.318231 0.889863 +vt 0.326036 0.880963 +vt 0.310881 0.877548 +vt 0.318231 0.889863 +vt 0.317035 0.868962 +vt 0.305396 0.874424 +vt 0.310881 0.877548 +vt 0.317035 0.868962 +vt 0.309811 0.894156 +vt 0.310881 0.877548 +vt 0.305396 0.874424 +vt 0.303901 0.895648 +vt 0.305396 0.874424 +vt 0.309524 0.911124 +vt 0.300537 0.909108 +vt 0.309524 0.911124 +vt 0.309083 0.929137 +vt 0.309524 0.911124 +vt 0.300537 0.909108 +vt 0.298528 0.922487 +vt 0.309083 0.929137 +vt 0.300537 0.909108 +vt 0.298115 0.941334 +vt 0.309083 0.929137 +vt 0.298528 0.922487 +vt 0.295550 0.920200 +vt 0.298115 0.941334 +vt 0.298528 0.922487 +vt 0.294936 0.938752 +vt 0.298115 0.941334 +vt 0.295550 0.920200 +vt 0.243698 0.909908 +vt 0.238791 0.889818 +vt 0.243110 0.888230 +vt 0.238791 0.909896 +vt 0.244381 0.926350 +vt 0.238791 0.926305 +vt 0.246192 0.937573 +vt 0.238791 0.937409 +vt 0.250641 0.950853 +vt 0.238791 0.950766 +vt 0.238791 0.988261 +vt 0.250641 0.950853 +vt 0.250460 0.988261 +vt 0.250641 0.950853 +vt 0.256765 0.956024 +vt 0.250641 0.950853 +vt 0.321122 0.792414 +vt 0.322264 0.788840 +vt 0.321122 0.792414 +vt 0.324019 0.788840 +vt 0.321122 0.792414 +vt 0.324009 0.782080 +vt 0.326331 0.782080 +vt 0.327414 0.772318 +vt 0.328175 0.772128 +vt 0.327645 0.759819 +vt 0.328368 0.759629 +vt 0.327321 0.747776 +vt 0.327474 0.747776 +vt 0.324546 0.833790 +vt 0.327155 0.833790 +vt 0.327052 0.821291 +vt 0.324075 0.845643 +vt 0.327155 0.833790 +vt 0.324546 0.833790 +vt 0.324075 0.845643 +vt 0.324546 0.833790 +vt 0.324075 0.845643 +vt 0.320306 0.845643 +vt 0.320169 0.853102 +vt 0.320306 0.845643 +vt 0.320169 0.853102 +vt 0.320306 0.845643 +vt 0.323089 0.853514 +vt 0.320169 0.853102 +vt 0.323089 0.853514 +vt 0.324859 0.853681 +vt 0.323089 0.853514 +vt 0.324859 0.853681 +vt 0.324715 0.862052 +vt 0.324859 0.853681 +vt 0.253286 0.534878 +vt 0.252682 0.535951 +vt 0.257497 0.545734 +vt 0.258376 0.542696 +vt 0.263281 0.554888 +vt 0.263702 0.550073 +vt 0.270029 0.559173 +vt 0.269716 0.553504 +vt 0.276642 0.553970 +vt 0.282838 0.550523 +vt 0.251100 0.537867 +vt 0.255906 0.551190 +vt 0.261642 0.563615 +vt 0.268972 0.569508 +vt 0.277433 0.568863 +vt 0.286845 0.805461 +vt 0.295621 0.838225 +vt 0.288469 0.838225 +vt 0.295621 0.805919 +vt 0.280606 0.782817 +vt 0.295621 0.805919 +vt 0.295621 0.780476 +vt 0.295621 0.805919 +vt 0.280606 0.782817 +vt 0.278181 0.766830 +vt 0.295621 0.780476 +vt 0.280606 0.782817 +vt 0.287994 0.765378 +vt 0.295621 0.780476 +vt 0.278181 0.766830 +vt 0.277337 0.762185 +vt 0.278181 0.766830 +vt 0.301991 0.750255 +vt 0.277337 0.762185 +vt 0.301991 0.746944 +vt 0.301991 0.750255 +vt 0.277337 0.762185 +vt 0.307262 0.746944 +vt 0.301991 0.750255 +vt 0.301991 0.746944 +vt 0.307262 0.737939 +vt 0.301991 0.746944 +vt 0.269115 0.955846 +vt 0.274074 0.975365 +vt 0.270235 0.941405 +vt 0.271762 0.918937 +vt 0.271595 0.905227 +vt 0.265364 0.917815 +vt 0.265039 0.902963 +vt 0.261126 0.908206 +vt 0.260713 0.899433 +vt 0.248297 0.746879 +vt 0.238791 0.744492 +vt 0.248297 0.746879 +vt 0.247456 0.749211 +vt 0.255458 0.762273 +vt 0.247456 0.749211 +vt 0.254338 0.766447 +vt 0.247456 0.749211 +vt 0.255458 0.762273 +vt 0.259173 0.767260 +vt 0.254338 0.766447 +vt 0.255458 0.762273 +vt 0.256191 0.769349 +vt 0.254338 0.766447 +vt 0.259173 0.767260 +vt 0.259173 0.767260 +vt 0.248936 0.880480 +vt 0.246283 0.868580 +vt 0.249934 0.876796 +vt 0.243653 0.881104 +vt 0.247937 0.884165 +vt 0.244329 0.891108 +vt 0.246760 0.895360 +vt 0.246921 0.909807 +vt 0.248014 0.924556 +vt 0.250662 0.939868 +vt 0.307128 0.998464 +vt 0.295736 0.983334 +vt 0.307087 0.987140 +vt 0.327545 0.998409 +vt 0.322267 0.987215 +vt 0.325796 0.967601 +vt 0.321231 0.964223 +vt 0.327509 0.942814 +vt 0.321231 0.964223 +vt 0.324223 0.942631 +vt 0.321231 0.964223 +vt 0.327509 0.942814 +vt 0.327460 0.910925 +vt 0.324223 0.942631 +vt 0.327509 0.942814 +vt 0.324223 0.942631 +vt 0.327460 0.910925 +vt 0.322264 0.788840 +vt 0.318831 0.792414 +vt 0.324019 0.788840 +vt 0.322264 0.788840 +vt 0.324009 0.782080 +vt 0.324019 0.788840 +vt 0.322264 0.788840 +vt 0.326331 0.782080 +vt 0.324019 0.788840 +vt 0.324009 0.782080 +vt 0.327414 0.772318 +vt 0.326331 0.782080 +vt 0.324009 0.782080 +vt 0.328175 0.772128 +vt 0.326331 0.782080 +vt 0.327414 0.772318 +vt 0.327645 0.759819 +vt 0.328175 0.772128 +vt 0.327414 0.772318 +vt 0.328368 0.759629 +vt 0.328175 0.772128 +vt 0.327645 0.759819 +vt 0.327321 0.747776 +vt 0.328368 0.759629 +vt 0.327645 0.759819 +vt 0.252682 0.535951 +vt 0.253286 0.534878 +vt 0.247649 0.522977 +vt 0.257497 0.545734 +vt 0.253286 0.534878 +vt 0.252682 0.535951 +vt 0.255906 0.551190 +vt 0.257497 0.545734 +vt 0.252682 0.535951 +vt 0.261642 0.563615 +vt 0.257497 0.545734 +vt 0.255906 0.551190 +vt 0.260012 0.572264 +vt 0.261642 0.563615 +vt 0.255906 0.551190 +vt 0.267620 0.579829 +vt 0.261642 0.563615 +vt 0.260012 0.572264 +vt 0.266442 0.585477 +vt 0.267620 0.579829 +vt 0.260012 0.572264 +vt 0.275704 0.583749 +vt 0.267620 0.579829 +vt 0.266442 0.585477 +vt 0.264714 0.888111 +vt 0.260439 0.893585 +vt 0.260713 0.899433 +vt 0.256093 0.876854 +vt 0.264714 0.888111 +vt 0.265589 0.878377 +vt 0.256093 0.876854 +vt 0.264714 0.888111 +vt 0.258929 0.870492 +vt 0.256093 0.876854 +vt 0.265589 0.878377 +vt 0.261320 0.853156 +vt 0.258929 0.870492 +vt 0.265589 0.878377 +vt 0.252444 0.859975 +vt 0.258929 0.870492 +vt 0.261320 0.853156 +vt 0.253440 0.842242 +vt 0.252444 0.859975 +vt 0.261320 0.853156 +vt 0.249328 0.857203 +vt 0.252444 0.859975 +vt 0.253440 0.842242 +vt 0.286845 0.805461 +vt 0.278077 0.804335 +vt 0.286845 0.805461 +vt 0.272204 0.782021 +vt 0.278077 0.804335 +vt 0.263570 0.781849 +vt 0.278077 0.804335 +vt 0.272204 0.782021 +vt 0.256191 0.769349 +vt 0.263570 0.781849 +vt 0.272204 0.782021 +vt 0.252940 0.771973 +vt 0.263570 0.781849 +vt 0.256191 0.769349 +vt 0.252940 0.771973 +vt 0.256191 0.769349 +vt 0.246568 0.755886 +vt 0.252940 0.771973 +vt 0.328175 0.821291 +vt 0.325726 0.811340 +vt 0.328175 0.821291 +vt 0.323326 0.811340 +vt 0.325726 0.811340 +vt 0.321873 0.804579 +vt 0.325726 0.811340 +vt 0.323326 0.811340 +vt 0.319469 0.804579 +vt 0.321873 0.804579 +vt 0.323326 0.811340 +vt 0.318768 0.801005 +vt 0.321873 0.804579 +vt 0.319469 0.804579 +vt 0.318768 0.801005 +vt 0.319469 0.804579 +vt 0.318768 0.801005 +vt 0.295621 0.838225 +vt 0.286845 0.805461 +vt 0.288469 0.838225 +vt 0.286845 0.805461 +vt 0.295621 0.838225 +vt 0.298400 0.833686 +vt 0.295621 0.838225 +vt 0.301991 0.822067 +vt 0.307262 0.822067 +vt 0.267782 0.832417 +vt 0.272075 0.865717 +vt 0.272839 0.835411 +vt 0.267014 0.860837 +vt 0.272075 0.865717 +vt 0.267782 0.832417 +vt 0.261835 0.827953 +vt 0.267782 0.832417 +vt 0.261320 0.853156 +vt 0.254021 0.821827 +vt 0.261320 0.853156 +vt 0.253440 0.842242 +vt 0.261320 0.853156 +vt 0.254021 0.821827 +vt 0.246837 0.842192 +vt 0.253440 0.842242 +vt 0.254021 0.821827 +vt 0.253440 0.842242 +vt 0.246837 0.842192 +vt 0.248297 0.746879 +vt 0.247456 0.749211 +vt 0.247456 0.749211 +vt 0.254338 0.766447 +vt 0.247456 0.749211 +vt 0.254338 0.766447 +vt 0.254338 0.766447 +vt 0.307262 0.780476 +vt 0.301991 0.750255 +vt 0.301991 0.765378 +vt 0.301991 0.750255 +vt 0.301991 0.780476 +vt 0.298400 0.780476 +vt 0.301991 0.780476 +vt 0.298400 0.805919 +vt 0.298400 0.780476 +vt 0.301991 0.780476 +vt 0.295621 0.805919 +vt 0.298400 0.780476 +vt 0.298400 0.805919 +vt 0.298400 0.833686 +vt 0.295621 0.805919 +vt 0.298400 0.805919 +vt 0.295621 0.805919 +vt 0.298400 0.833686 +vt 0.263281 0.554888 +vt 0.263702 0.550073 +vt 0.258376 0.542696 +vt 0.270029 0.559173 +vt 0.263702 0.550073 +vt 0.263281 0.554888 +vt 0.268972 0.569508 +vt 0.270029 0.559173 +vt 0.263281 0.554888 +vt 0.277433 0.568863 +vt 0.270029 0.559173 +vt 0.268972 0.569508 +vt 0.276622 0.578481 +vt 0.277433 0.568863 +vt 0.268972 0.569508 +vt 0.285461 0.564519 +vt 0.277433 0.568863 +vt 0.276622 0.578481 +vt 0.285177 0.566397 +vt 0.285461 0.564519 +vt 0.276622 0.578481 +vt 0.289316 0.540202 +vt 0.285461 0.564519 +vt 0.285177 0.566397 +vt 0.257497 0.545734 +vt 0.258376 0.542696 +vt 0.253286 0.534878 +vt 0.263281 0.554888 +vt 0.258376 0.542696 +vt 0.257497 0.545734 +vt 0.261642 0.563615 +vt 0.263281 0.554888 +vt 0.257497 0.545734 +vt 0.268972 0.569508 +vt 0.263281 0.554888 +vt 0.261642 0.563615 +vt 0.267620 0.579829 +vt 0.268972 0.569508 +vt 0.261642 0.563615 +vt 0.276622 0.578481 +vt 0.268972 0.569508 +vt 0.267620 0.579829 +vt 0.275704 0.583749 +vt 0.276622 0.578481 +vt 0.267620 0.579829 +vt 0.285177 0.566397 +vt 0.276622 0.578481 +vt 0.275704 0.583749 +vt 0.265364 0.917815 +vt 0.265039 0.902963 +vt 0.261126 0.908206 +vt 0.271762 0.918937 +vt 0.265039 0.902963 +vt 0.265364 0.917815 +vt 0.264931 0.937282 +vt 0.271762 0.918937 +vt 0.265364 0.917815 +vt 0.270235 0.941405 +vt 0.271762 0.918937 +vt 0.261932 0.954937 +vt 0.270235 0.941405 +vt 0.269115 0.955846 +vt 0.270235 0.941405 +vt 0.266149 0.988261 +vt 0.269115 0.955846 +vt 0.272733 0.988261 +vt 0.269115 0.955846 +vt 0.326094 0.739571 +vt 0.324729 0.732386 +vt 0.324715 0.731367 +vt 0.326025 0.740081 +vt 0.324729 0.732386 +vt 0.326094 0.739571 +vt 0.327321 0.747776 +vt 0.326025 0.740081 +vt 0.326094 0.739571 +vt 0.324092 0.747776 +vt 0.326025 0.740081 +vt 0.327321 0.747776 +vt 0.324610 0.759629 +vt 0.324092 0.747776 +vt 0.327321 0.747776 +vt 0.320459 0.759629 +vt 0.324092 0.747776 +vt 0.320698 0.772128 +vt 0.320459 0.759629 +vt 0.107694 0.336850 +vt 0.131476 0.320899 +vt 0.131476 0.336850 +vt 0.107694 0.320899 +vt 0.084006 0.336850 +vt 0.084006 0.320899 +vt 0.072020 0.320899 +vt 0.084006 0.320899 +vt 0.072020 0.320899 +vt 0.084006 0.320899 +vt 0.254531 0.944175 +vt 0.258593 0.941822 +vt 0.261066 0.935052 +vt 0.265364 0.917815 +vt 0.261538 0.916978 +vt 0.265364 0.917815 +vt 0.261126 0.908206 +vt 0.265364 0.917815 +vt 0.307262 0.780476 +vt 0.301991 0.765378 +vt 0.307262 0.780476 +vt 0.301991 0.765378 +vt 0.307262 0.780476 +vt 0.287994 0.765378 +vt 0.301991 0.765378 +vt 0.287994 0.765378 +vt 0.287994 0.765378 +vt 0.270029 0.559173 +vt 0.269716 0.553504 +vt 0.263702 0.550073 +vt 0.277417 0.559242 +vt 0.269716 0.553504 +vt 0.270029 0.559173 +vt 0.277433 0.568863 +vt 0.277417 0.559242 +vt 0.270029 0.559173 +vt 0.284684 0.559677 +vt 0.277417 0.559242 +vt 0.277433 0.568863 +vt 0.285461 0.564519 +vt 0.284684 0.559677 +vt 0.277433 0.568863 +vt 0.289316 0.540202 +vt 0.284684 0.559677 +vt 0.285461 0.564519 +vt 0.250641 0.950853 +vt 0.246192 0.937573 +vt 0.250641 0.950853 +vt 0.250662 0.939868 +vt 0.246192 0.937573 +vt 0.250641 0.950853 +vt 0.244381 0.926350 +vt 0.246192 0.937573 +vt 0.250662 0.939868 +vt 0.248014 0.924556 +vt 0.244381 0.926350 +vt 0.250662 0.939868 +vt 0.246921 0.909807 +vt 0.244381 0.926350 +vt 0.248014 0.924556 +vt 0.260012 0.572264 +vt 0.258843 0.576968 +vt 0.266442 0.585477 +vt 0.254330 0.556527 +vt 0.258843 0.576968 +vt 0.260012 0.572264 +vt 0.255906 0.551190 +vt 0.254330 0.556527 +vt 0.260012 0.572264 +vt 0.251100 0.537867 +vt 0.254330 0.556527 +vt 0.255906 0.551190 +vt 0.252682 0.535951 +vt 0.251100 0.537867 +vt 0.255906 0.551190 +vt 0.247649 0.522977 +vt 0.251100 0.537867 +vt 0.252682 0.535951 +vt 0.299468 0.975881 +vt 0.307128 0.998464 +vt 0.295736 0.983334 +vt 0.307087 0.987140 +vt 0.307128 0.998464 +vt 0.299468 0.975881 +vt 0.307087 0.987140 +vt 0.299468 0.975881 +vt 0.322267 0.987215 +vt 0.307087 0.987140 +vt 0.322267 0.987215 +vt 0.322267 0.987215 +vt 0.280606 0.782817 +vt 0.288502 0.838131 +vt 0.286926 0.865348 +vt 0.295621 0.838027 +vt 0.295621 0.870041 +vt 0.260439 0.893585 +vt 0.307262 0.746944 +vt 0.307262 0.780476 +vt 0.307262 0.746944 +vt 0.307262 0.737939 +vt 0.307262 0.746944 +vt 0.301991 0.737939 +vt 0.307262 0.737939 +vt 0.307262 0.737939 +vt 0.301991 0.746944 +vt 0.265039 0.902963 +vt 0.260713 0.899433 +vt 0.261126 0.908206 +vt 0.264714 0.888111 +vt 0.260713 0.899433 +vt 0.265039 0.902963 +vt 0.271428 0.891517 +vt 0.264714 0.888111 +vt 0.265039 0.902963 +vt 0.271627 0.882871 +vt 0.264714 0.888111 +vt 0.271428 0.891517 +vt 0.279004 0.884609 +vt 0.271627 0.882871 +vt 0.271428 0.891517 +vt 0.272075 0.865717 +vt 0.271627 0.882871 +vt 0.279004 0.884609 +vt 0.319666 0.788840 +vt 0.322264 0.788840 +vt 0.318831 0.792414 +vt 0.324009 0.782080 +vt 0.322264 0.788840 +vt 0.319666 0.788840 +vt 0.320386 0.782080 +vt 0.324009 0.782080 +vt 0.319666 0.788840 +vt 0.324605 0.772128 +vt 0.324009 0.782080 +vt 0.320386 0.782080 +vt 0.320698 0.772128 +vt 0.320386 0.782080 +vt 0.320698 0.772128 +vt 0.243698 0.909908 +vt 0.243110 0.888230 +vt 0.243698 0.909908 +vt 0.244329 0.891108 +vt 0.243110 0.888230 +vt 0.243698 0.909908 +vt 0.243653 0.881104 +vt 0.243110 0.888230 +vt 0.244329 0.891108 +vt 0.247937 0.884165 +vt 0.243653 0.881104 +vt 0.244329 0.891108 +vt 0.248936 0.880480 +vt 0.243653 0.881104 +vt 0.247937 0.884165 +vt 0.319469 0.804579 +vt 0.320023 0.811340 +vt 0.319469 0.804579 +vt 0.323326 0.811340 +vt 0.320023 0.811340 +vt 0.319469 0.804579 +vt 0.324249 0.821291 +vt 0.320023 0.811340 +vt 0.323326 0.811340 +vt 0.324249 0.821291 +vt 0.323326 0.811340 +vt 0.267014 0.860837 +vt 0.267014 0.860837 +vt 0.267014 0.860837 +vt 0.242253 0.800177 +vt 0.248335 0.800867 +vt 0.247526 0.807069 +vt 0.242253 0.800177 +vt 0.242648 0.807233 +vt 0.247526 0.807069 +vt 0.242253 0.800177 +vt 0.246837 0.842192 +vt 0.247526 0.807069 +vt 0.242648 0.807233 +vt 0.238791 0.824857 +vt 0.246837 0.842192 +vt 0.242648 0.807233 +vt 0.261932 0.954937 +vt 0.250460 0.988261 +vt 0.256735 0.956024 +vt 0.266149 0.988261 +vt 0.250460 0.988261 +vt 0.261932 0.954937 +vt 0.266149 0.988261 +vt 0.261932 0.954937 +vt 0.272733 0.988261 +vt 0.266149 0.988261 +vt 0.272733 0.988261 +vt 0.270235 0.941405 +vt 0.279050 0.921809 +vt 0.271762 0.918937 +vt 0.279042 0.957224 +vt 0.279050 0.921809 +vt 0.270235 0.941405 +vt 0.269115 0.955846 +vt 0.279042 0.957224 +vt 0.270235 0.941405 +vt 0.279076 0.964797 +vt 0.279042 0.957224 +vt 0.269115 0.955846 +vt 0.274074 0.975365 +vt 0.279076 0.964797 +vt 0.269115 0.955846 +vt 0.269089 0.802840 +vt 0.263570 0.781849 +vt 0.264323 0.803475 +vt 0.278077 0.804335 +vt 0.263570 0.781849 +vt 0.269089 0.802840 +vt 0.278729 0.837282 +vt 0.278077 0.804335 +vt 0.269089 0.802840 +vt 0.286845 0.805461 +vt 0.278077 0.804335 +vt 0.278729 0.837282 +vt 0.288502 0.838131 +vt 0.286845 0.805461 +vt 0.278729 0.837282 +vt 0.254021 0.821827 +vt 0.247526 0.807069 +vt 0.246837 0.842192 +vt 0.255145 0.807754 +vt 0.247526 0.807069 +vt 0.254021 0.821827 +vt 0.254021 0.821827 +vt 0.258445 0.802905 +vt 0.267782 0.832417 +vt 0.258445 0.802905 +vt 0.324610 0.759629 +vt 0.324610 0.759629 +vt 0.324610 0.759629 +vt 0.324605 0.772128 +vt 0.324605 0.772128 +vt 0.324605 0.772128 +vt 0.261932 0.954937 +vt 0.264931 0.937282 +vt 0.261932 0.954937 +vt 0.258593 0.941822 +vt 0.264931 0.937282 +vt 0.261932 0.954937 +vt 0.261066 0.935052 +vt 0.264931 0.937282 +vt 0.258593 0.941822 +vt 0.317951 0.746510 +vt 0.319952 0.747776 +vt 0.323161 0.736013 +vt 0.319952 0.747776 +vt 0.324092 0.747776 +vt 0.319952 0.747776 +vt 0.323161 0.736013 +vt 0.324605 0.772128 +vt 0.324610 0.759629 +vt 0.324605 0.772128 +vt 0.324610 0.759629 +vt 0.324605 0.772128 +vt 0.324610 0.759629 +vt 0.332443 0.942673 +vt 0.325796 0.967601 +vt 0.327545 0.998409 +vt 0.325796 0.967601 +vt 0.322267 0.987215 +vt 0.325796 0.967601 +vt 0.327545 0.998409 +vt 0.332443 0.942673 +vt 0.327509 0.942814 +vt 0.332443 0.942673 +vt 0.332443 0.905196 +vt 0.327509 0.942814 +vt 0.332443 0.942673 +vt 0.327460 0.910925 +vt 0.327509 0.942814 +vt 0.332443 0.905196 +vt 0.295339 0.905886 +vt 0.303901 0.895648 +vt 0.303901 0.895648 +vt 0.303901 0.895648 +vt 0.324019 0.788840 +vt 0.326874 0.782080 +vt 0.324019 0.788840 +vt 0.326331 0.782080 +vt 0.324019 0.788840 +vt 0.328175 0.772128 +vt 0.326331 0.782080 +vt 0.327414 0.772318 +vt 0.324009 0.782080 +vt 0.327645 0.759819 +vt 0.327414 0.772318 +vt 0.327645 0.759819 +vt 0.327321 0.747776 +vt 0.327645 0.759819 +vt 0.255145 0.807754 +vt 0.261835 0.827953 +vt 0.255145 0.807754 +vt 0.261835 0.827953 +vt 0.255145 0.807754 +vt 0.261835 0.827953 +vt 0.242648 0.807233 +vt 0.242253 0.800177 +vt 0.242648 0.807233 +vt 0.318857 0.938198 +vt 0.318857 0.938198 +vt 0.323552 0.918475 +vt 0.318857 0.938198 +vt 0.323552 0.918475 +vt 0.254330 0.556527 +vt 0.253473 0.559399 +vt 0.258843 0.576968 +vt 0.250047 0.539728 +vt 0.253473 0.559399 +vt 0.254330 0.556527 +vt 0.251100 0.537867 +vt 0.250047 0.539728 +vt 0.254330 0.556527 +vt 0.247649 0.522977 +vt 0.250047 0.539728 +vt 0.251100 0.537867 +vt 0.298115 0.941334 +vt 0.309083 0.929137 +vt 0.300785 0.962521 +vt 0.298115 0.941334 +vt 0.294936 0.938752 +vt 0.300785 0.962521 +vt 0.298115 0.941334 +vt 0.300491 0.972497 +vt 0.300785 0.962521 +vt 0.294936 0.938752 +vt 0.318157 0.917748 +vt 0.309524 0.911124 +vt 0.309083 0.929137 +vt 0.314838 0.901584 +vt 0.309524 0.911124 +vt 0.318157 0.917748 +vt 0.318231 0.889863 +vt 0.314838 0.901584 +vt 0.318157 0.917748 +vt 0.310881 0.877548 +vt 0.314838 0.901584 +vt 0.318231 0.889863 +vt 0.316774 0.955723 +vt 0.321231 0.964223 +vt 0.324223 0.942631 +vt 0.315411 0.980287 +vt 0.321231 0.964223 +vt 0.316774 0.955723 +vt 0.311938 0.969699 +vt 0.315411 0.980287 +vt 0.316774 0.955723 +vt 0.306022 0.981785 +vt 0.315411 0.980287 +vt 0.311938 0.969699 +vt 0.244381 0.926350 +vt 0.243698 0.909908 +vt 0.244381 0.926350 +vt 0.246921 0.909807 +vt 0.243698 0.909908 +vt 0.244381 0.926350 +vt 0.246760 0.895360 +vt 0.243698 0.909908 +vt 0.246921 0.909807 +vt 0.277417 0.559242 +vt 0.276642 0.553970 +vt 0.269716 0.553504 +vt 0.283947 0.554349 +vt 0.276642 0.553970 +vt 0.277417 0.559242 +vt 0.284684 0.559677 +vt 0.283947 0.554349 +vt 0.277417 0.559242 +vt 0.289316 0.540202 +vt 0.283947 0.554349 +vt 0.284684 0.559677 +vt 0.254531 0.944175 +vt 0.256765 0.956024 +vt 0.254531 0.944175 +vt 0.307262 0.805763 +vt 0.301991 0.780476 +vt 0.301991 0.805888 +vt 0.301991 0.780476 +vt 0.307262 0.805763 +vt 0.307262 0.822067 +vt 0.301991 0.805888 +vt 0.307262 0.805763 +vt 0.301991 0.822067 +vt 0.301991 0.805888 +vt 0.307262 0.822067 +vt 0.243938 0.783302 +vt 0.238791 0.781607 +vt 0.246033 0.768224 +vt 0.248098 0.786064 +vt 0.246033 0.768224 +vt 0.252445 0.783194 +vt 0.246033 0.768224 +vt 0.318857 0.938198 +vt 0.323552 0.918475 +vt 0.318857 0.938198 +vt 0.323552 0.918475 +vt 0.323552 0.918475 +vt 0.131476 0.320899 +vt 0.107694 0.336850 +vt 0.131476 0.336850 +vt 0.107694 0.320899 +vt 0.107694 0.336850 +vt 0.131476 0.320899 +vt 0.131476 0.320899 +vt 0.107694 0.320899 +vt 0.131476 0.320899 +vt 0.107694 0.320899 +vt 0.107694 0.320899 +vt 0.131476 0.320899 +vt 0.107694 0.320899 +vt 0.084006 0.336850 +vt 0.107694 0.336850 +vt 0.084006 0.320899 +vt 0.084006 0.336850 +vt 0.107694 0.320899 +vt 0.107694 0.320899 +vt 0.084006 0.320899 +vt 0.107694 0.320899 +vt 0.084006 0.320899 +vt 0.084006 0.320899 +vt 0.107694 0.320899 +vt 0.131476 0.320899 +vt 0.107694 0.320899 +vt 0.131476 0.320899 +vt 0.107694 0.320899 +vt 0.084006 0.320899 +vt 0.107694 0.320899 +vt 0.320964 0.801005 +vt 0.321873 0.804579 +vt 0.318768 0.801005 +vt 0.323628 0.804579 +vt 0.321873 0.804579 +vt 0.320964 0.801005 +vt 0.324463 0.804579 +vt 0.323628 0.804579 +vt 0.320964 0.801005 +vt 0.326874 0.811340 +vt 0.323628 0.804579 +vt 0.324463 0.804579 +vt 0.307446 0.946584 +vt 0.307446 0.946584 +vt 0.307446 0.946584 +vt 0.303901 0.895648 +vt 0.309811 0.894156 +vt 0.303901 0.895648 +vt 0.309811 0.894156 +vt 0.303901 0.895648 +vt 0.309811 0.894156 +vt 0.300537 0.909108 +vt 0.295550 0.920200 +vt 0.298528 0.922487 +vt 0.295339 0.905886 +vt 0.295550 0.920200 +vt 0.300537 0.909108 +vt 0.295339 0.905886 +vt 0.300537 0.909108 +vt 0.320023 0.811340 +vt 0.320375 0.821291 +vt 0.320023 0.811340 +vt 0.324249 0.821291 +vt 0.320375 0.821291 +vt 0.320023 0.811340 +vt 0.298400 0.805919 +vt 0.301991 0.822067 +vt 0.298400 0.833686 +vt 0.301991 0.805888 +vt 0.301991 0.822067 +vt 0.298400 0.805919 +vt 0.301991 0.780476 +vt 0.301991 0.805888 +vt 0.298400 0.805919 +vt 0.249328 0.857203 +vt 0.253255 0.873709 +vt 0.322103 0.861385 +vt 0.324859 0.853681 +vt 0.323089 0.853514 +vt 0.324859 0.853681 +vt 0.322103 0.861385 +vt 0.320169 0.853102 +vt 0.323089 0.853514 +vt 0.322103 0.861385 +vt 0.324075 0.845643 +vt 0.326308 0.845643 +vt 0.327155 0.833790 +vt 0.326308 0.845643 +vt 0.324075 0.845643 +vt 0.324075 0.845643 +vt 0.320169 0.853102 +vt 0.320031 0.860561 +vt 0.320169 0.853102 +vt 0.322103 0.861385 +vt 0.320031 0.860561 +vt 0.320169 0.853102 +vt 0.261538 0.916978 +vt 0.261066 0.935052 +vt 0.261538 0.916978 +vt 0.264931 0.937282 +vt 0.261066 0.935052 +vt 0.271762 0.918937 +vt 0.271428 0.891517 +vt 0.265039 0.902963 +vt 0.278964 0.893360 +vt 0.271428 0.891517 +vt 0.271762 0.918937 +vt 0.279050 0.921809 +vt 0.278964 0.893360 +vt 0.271762 0.918937 +vt 0.271627 0.882871 +vt 0.265589 0.878377 +vt 0.264714 0.888111 +vt 0.265589 0.878377 +vt 0.271627 0.882871 +vt 0.272075 0.865717 +vt 0.271627 0.882871 +vt 0.286926 0.865348 +vt 0.278803 0.865380 +vt 0.286297 0.886857 +vt 0.278729 0.837282 +vt 0.278803 0.865380 +vt 0.286926 0.865348 +vt 0.288502 0.838131 +vt 0.278729 0.837282 +vt 0.286926 0.865348 +vt 0.286926 0.865348 +vt 0.295621 0.838027 +vt 0.288502 0.838131 +vt 0.295621 0.870041 +vt 0.295621 0.838027 +vt 0.286926 0.865348 +vt 0.286297 0.886857 +vt 0.295621 0.870041 +vt 0.286926 0.865348 +vt 0.248297 0.746879 +vt 0.248297 0.746879 +vt 0.248297 0.746879 +vt 0.261835 0.827953 +vt 0.267014 0.860837 +vt 0.261835 0.827953 +vt 0.267014 0.860837 +vt 0.261835 0.827953 +vt 0.307446 0.946584 +vt 0.307446 0.946584 +vt 0.307446 0.946584 +vt 0.084006 0.320899 +vt 0.084006 0.336850 +vt 0.072020 0.320899 +vt 0.084006 0.320899 +vt 0.084006 0.320899 +vt 0.072020 0.320899 +vt 0.084006 0.320899 +vt 0.324223 0.942631 +vt 0.316774 0.955723 +vt 0.324223 0.942631 +vt 0.306022 0.981785 +vt 0.306022 0.981785 +vt 0.315411 0.980287 +vt 0.306022 0.981785 +vt 0.321231 0.964223 +vt 0.315411 0.980287 +vt 0.324953 0.579718 +vt 0.317470 0.582521 +vt 0.324953 0.582513 +vt 0.317470 0.579718 +vt 0.307087 0.987140 +vt 0.327545 0.998409 +vt 0.307128 0.998464 +vt 0.322267 0.987215 +vt 0.327545 0.998409 +vt 0.307087 0.987140 +vt 0.295621 0.780476 +vt 0.298400 0.780476 +vt 0.295621 0.805919 +vt 0.298400 0.780476 +vt 0.295621 0.780476 +vt 0.298400 0.780476 +vt 0.301991 0.750255 +vt 0.300785 0.962521 +vt 0.305873 0.970206 +vt 0.300491 0.972497 +vt 0.305873 0.970206 +vt 0.300785 0.962521 +vt 0.287994 0.765378 +vt 0.287994 0.765378 +vt 0.301991 0.765378 +vt 0.287994 0.765378 +vt 0.301991 0.765378 +vt 0.301991 0.746944 +vt 0.256191 0.769349 +vt 0.272204 0.782021 +vt 0.256191 0.769349 +vt 0.264931 0.937282 +vt 0.269902 0.746944 +vt 0.301991 0.746944 +vt 0.277337 0.762185 +vt 0.301991 0.746944 +vt 0.269902 0.746944 +vt 0.286138 0.938424 +vt 0.285922 0.957197 +vt 0.295621 0.884234 +vt 0.238791 0.797185 +vt 0.242018 0.799325 +vt 0.242018 0.799325 +vt 0.247791 0.800330 +vt 0.242018 0.799325 +vt 0.244329 0.891108 +vt 0.246760 0.895360 +vt 0.247937 0.884165 +vt 0.243698 0.909908 +vt 0.246760 0.895360 +vt 0.244329 0.891108 +vt 0.309811 0.894156 +vt 0.309811 0.894156 +vt 0.324715 0.862052 +vt 0.326094 0.853848 +vt 0.324715 0.862052 +vt 0.320964 0.792414 +vt 0.321122 0.792414 +vt 0.324463 0.788840 +vt 0.321122 0.792414 +vt 0.320964 0.792414 +vt 0.246192 0.937573 +vt 0.244381 0.926350 +vt 0.246192 0.937573 +vt 0.324463 0.788840 +vt 0.321122 0.792414 +vt 0.326874 0.782080 +vt 0.324463 0.788840 +vt 0.326874 0.782080 +vt 0.326874 0.782080 +vt 0.261932 0.954937 +vt 0.254531 0.944175 +vt 0.258593 0.941822 +vt 0.256765 0.956024 +vt 0.254531 0.944175 +vt 0.261932 0.954937 +vt 0.325796 0.967601 +vt 0.322267 0.987215 +vt 0.325796 0.967601 +vt 0.327474 0.747776 +vt 0.327321 0.747776 +vt 0.326094 0.739571 +vt 0.328368 0.759629 +vt 0.327321 0.747776 +vt 0.327474 0.747776 +vt 0.318768 0.801005 +vt 0.320964 0.801005 +vt 0.318768 0.801005 +vt 0.295621 0.884234 +vt 0.286297 0.886857 +vt 0.285666 0.894376 +vt 0.295621 0.870041 +vt 0.286297 0.886857 +vt 0.295621 0.884234 +vt 0.259340 0.783451 +vt 0.263570 0.781849 +vt 0.252940 0.771973 +vt 0.264323 0.803475 +vt 0.263570 0.781849 +vt 0.259340 0.783451 +vt 0.319952 0.747776 +vt 0.320459 0.759629 +vt 0.324092 0.747776 +vt 0.320459 0.759629 +vt 0.319952 0.747776 +vt 0.299468 0.975881 +vt 0.299468 0.975881 +vt 0.243938 0.783302 +vt 0.243938 0.783302 +vt 0.326046 0.876066 +vt 0.332478 0.871578 +vt 0.317729 0.868690 +vt 0.326036 0.880963 +vt 0.332478 0.871578 +vt 0.326046 0.876066 +vt 0.246283 0.868580 +vt 0.252444 0.859975 +vt 0.249934 0.876796 +vt 0.252444 0.859975 +vt 0.246283 0.868580 +vt 0.253255 0.873709 +vt 0.252444 0.859975 +vt 0.249934 0.876796 +vt 0.256093 0.876854 +vt 0.252444 0.859975 +vt 0.253255 0.873709 +vt 0.317470 0.582521 +vt 0.317470 0.579718 +vt 0.324953 0.579718 +vt 0.311448 0.579718 +vt 0.317470 0.579718 +vt 0.317470 0.582521 +vt 0.256735 0.956024 +vt 0.286138 0.938424 +vt 0.283841 0.956948 +vt 0.285922 0.957197 +vt 0.283007 0.924172 +vt 0.283841 0.956948 +vt 0.286138 0.938424 +vt 0.302847 0.868819 +vt 0.305396 0.874424 +vt 0.317035 0.868962 +vt 0.298677 0.879312 +vt 0.305396 0.874424 +vt 0.302847 0.868819 +vt 0.072020 0.336850 +vt 0.084006 0.336850 +vt 0.314838 0.901584 +vt 0.309524 0.911124 +vt 0.310881 0.877548 +vt 0.314838 0.901584 +vt 0.323628 0.804579 +vt 0.325726 0.811340 +vt 0.321873 0.804579 +vt 0.326874 0.811340 +vt 0.325726 0.811340 +vt 0.323628 0.804579 +vt 0.267014 0.860837 +vt 0.248098 0.786064 +vt 0.243938 0.783302 +vt 0.248098 0.786064 +vt 0.250460 0.988261 +vt 0.256765 0.956024 +vt 0.250460 0.988261 +vt 0.249328 0.857203 +vt 0.249328 0.857203 +vt 0.248335 0.800867 +vt 0.247791 0.800330 +vt 0.248335 0.800867 +vt 0.248936 0.880480 +vt 0.246283 0.868580 +vt 0.243653 0.881104 +vt 0.249934 0.876796 +vt 0.246283 0.868580 +vt 0.248936 0.880480 +vt 0.298677 0.879312 +vt 0.305396 0.874424 +vt 0.295339 0.905886 +vt 0.298677 0.879312 +vt 0.249473 0.540724 +vt 0.250047 0.539728 +vt 0.247649 0.522977 +vt 0.253473 0.559399 +vt 0.250047 0.539728 +vt 0.249473 0.540724 +vt 0.250641 0.950853 +vt 0.250662 0.939868 +vt 0.250641 0.950853 +vt 0.326025 0.740081 +vt 0.323161 0.736013 +vt 0.324729 0.732386 +vt 0.324092 0.747776 +vt 0.323161 0.736013 +vt 0.326025 0.740081 +vt 0.282838 0.550523 +vt 0.283947 0.554349 +vt 0.289316 0.540202 +vt 0.276642 0.553970 +vt 0.283947 0.554349 +vt 0.282838 0.550523 +vt 0.272204 0.782021 +vt 0.260439 0.893585 +vt 0.328175 0.821291 +vt 0.325726 0.811340 +vt 0.326874 0.811340 +vt 0.326094 0.853848 +vt 0.327474 0.845643 +vt 0.269115 0.955846 +vt 0.274074 0.975365 +vt 0.271428 0.891517 +vt 0.278964 0.893360 +vt 0.279004 0.884609 +vt 0.261320 0.853156 +vt 0.265589 0.878377 +vt 0.258929 0.870492 +vt 0.252444 0.859975 +vt 0.256093 0.876854 +vt 0.238791 0.798956 +vt 0.238791 0.802277 +vt 0.244268 0.802623 +vt 0.244268 0.802623 +vt 0.244131 0.799885 +vt 0.244268 0.802623 +vt 0.248823 0.802817 +vt 0.244268 0.802623 +vt 0.249726 0.801630 +vt 0.255145 0.807754 +vt 0.251385 0.792084 +vt 0.249275 0.802224 +vt 0.311463 0.578279 +vt 0.311463 0.468112 +vt 0.317853 0.471226 +vt 0.317853 0.471226 +vt 0.317494 0.578304 +vt 0.317853 0.471226 +vt 0.324933 0.578250 +vt 0.317853 0.471226 +vt 0.248335 0.800867 +vt 0.247791 0.800330 +vt 0.248335 0.800867 +vt 0.255145 0.807754 +vt 0.251385 0.792084 +vt 0.252445 0.783194 +vt 0.258445 0.802905 +vt 0.252445 0.783194 +vt 0.251385 0.792084 +vt 0.249726 0.801630 +vt 0.258445 0.802905 +vt 0.251385 0.792084 +vt 0.324933 0.578250 +vt 0.328944 0.493465 +vt 0.330653 0.496967 +vt 0.327236 0.489964 +vt 0.324933 0.578250 +vt 0.324933 0.578250 +vt 0.327236 0.489964 +vt 0.317853 0.471226 +vt 0.328944 0.493465 +vt 0.327236 0.489964 +vt 0.330653 0.496967 +vt 0.328944 0.493465 +vt 0.311448 0.582517 +vt 0.317470 0.582521 +vt 0.244131 0.799885 +vt 0.248823 0.802817 +vt 0.244131 0.799885 +vt 0.324953 0.582513 +vt 0.324953 0.579718 +vt 0.325433 0.580454 +vt 0.317470 0.582521 +vt 0.324953 0.579718 +vt 0.324953 0.582513 +vt 0.249726 0.801630 +vt 0.247526 0.807069 +vt 0.249726 0.801630 +vt 0.249726 0.801630 +vt 0.247526 0.807069 +vt 0.258445 0.802905 +vt 0.249726 0.801630 +vt 0.248098 0.786064 +vt 0.317494 0.578304 +vt 0.324933 0.578250 +vt 0.317494 0.578304 +vt 0.251385 0.792084 +vt 0.249275 0.802224 +vt 0.249726 0.801630 +vt 0.248823 0.802817 +vt 0.249275 0.802224 +vt 0.251385 0.792084 +vt 0.325433 0.580454 +vt 0.248082 0.790998 +vt 0.251385 0.792084 +vt 0.248449 0.800904 +vt 0.251385 0.792084 +vt 0.248823 0.802817 +vt 0.251385 0.792084 +vt 0.244131 0.799885 +vt 0.248823 0.802817 +vt 0.248082 0.790998 +vt 0.243938 0.783302 +vt 0.248098 0.786064 +vt 0.243957 0.789441 +vt 0.243938 0.783302 +vt 0.248082 0.790998 +vt 0.248449 0.800904 +vt 0.248082 0.790998 +vt 0.248449 0.800904 +vt 0.248449 0.800904 +vt 0.244131 0.799885 +vt 0.238791 0.788463 +vt 0.243957 0.789441 +vt 0.244131 0.799885 +vt 0.243957 0.789441 +vt 0.244131 0.799885 +vt 0.243957 0.789441 +vt 0.243938 0.783302 +vt 0.243957 0.789441 +vt 0.243957 0.789441 +vt 0.248082 0.790998 +vt 0.248098 0.786064 +vt 0.248449 0.800904 +vt 0.248082 0.790998 +vt 0.248449 0.800904 +vt 0.243938 0.783302 +vt 0.368910 0.876776 +vt 0.376138 0.873873 +vt 0.371296 0.862137 +vt 0.375780 0.897365 +vt 0.360639 0.926249 +vt 0.378371 0.925378 +vt 0.376186 0.952870 +vt 0.382860 0.943681 +vt 0.380759 0.960802 +vt 0.377257 0.975165 +vt 0.370030 0.972687 +vt 0.361500 0.980122 +vt 0.352778 0.973484 +vt 0.356131 0.993947 +vt 0.350682 0.987730 +vt 0.343345 0.927534 +vt 0.345330 0.899507 +vt 0.339095 0.910081 +vt 0.345330 0.899507 +vt 0.343345 0.927534 +vt 0.346122 0.954420 +vt 0.343345 0.927534 +vt 0.346122 0.954420 +vt 0.345956 0.977097 +vt 0.346122 0.954420 +vt 0.345956 0.977097 +vt 0.345330 0.899507 +vt 0.341032 0.892127 +vt 0.339095 0.910081 +vt 0.344320 0.876514 +vt 0.341032 0.892127 +vt 0.345330 0.899507 +vt 0.351380 0.878048 +vt 0.345330 0.899507 +vt 0.348695 0.863959 +vt 0.354023 0.856166 +vt 0.346122 0.954420 +vt 0.342124 0.963339 +vt 0.345956 0.977097 +vt 0.339662 0.946763 +vt 0.346122 0.954420 +vt 0.343345 0.927534 +vt 0.346122 0.954420 +vt 0.338526 0.928680 +vt 0.343345 0.927534 +vt 0.339095 0.910081 +vt 0.343345 0.927534 +vt 0.345330 0.899507 +vt 0.359976 0.869622 +vt 0.365695 0.855248 +vt 0.372808 0.986422 +vt 0.367525 0.993289 +vt 0.361862 0.996115 +vt 0.383673 0.925173 +vt 0.382591 0.906491 +vt 0.383673 0.925173 +vt 0.382591 0.906491 +vt 0.380056 0.888836 +vt 0.382591 0.906491 +vt 0.359809 0.852883 +vt 0.359809 0.852883 +vt 0.380056 0.888836 +vt 0.481700 0.753131 +vt 0.468484 0.794278 +vt 0.468723 0.742404 +vt 0.480518 0.809914 +vt 0.494176 0.764702 +vt 0.493354 0.823966 +vt 0.510135 0.771381 +vt 0.510114 0.832468 +vt 0.455335 0.777109 +vt 0.451416 0.805291 +vt 0.441073 0.792773 +vt 0.457001 0.818480 +vt 0.467201 0.836968 +vt 0.478914 0.852812 +vt 0.444007 0.765678 +vt 0.433923 0.792959 +vt 0.617119 0.092642 +vt 0.616946 0.118228 +vt 0.601778 0.116796 +vt 0.642380 0.089071 +vt 0.465849 0.876372 +vt 0.457119 0.857447 +vt 0.477766 0.895439 +vt 0.491231 0.913030 +vt 0.494364 0.871486 +vt 0.510325 0.925896 +vt 0.510811 0.881395 +vt 0.532021 0.921485 +vt 0.531875 0.875894 +vt 0.548738 0.904855 +vt 0.549248 0.882822 +vt 0.558035 0.884887 +vt 0.549759 0.856100 +vt 0.556350 0.845199 +vt 0.554455 0.804074 +vt 0.579805 0.820201 +vt 0.579652 0.771697 +vt 0.592683 0.808109 +vt 0.603602 0.767589 +vt 0.604101 0.766929 +vt 0.641504 0.118912 +vt 0.640818 0.142998 +vt 0.617657 0.145053 +vt 0.664587 0.112779 +vt 0.664587 0.086049 +vt 0.643979 0.064316 +vt 0.664587 0.064099 +vt 0.664587 0.048518 +vt 0.438208 0.819515 +vt 0.447684 0.836792 +vt 0.429711 0.016592 +vt 0.426207 0.011382 +vt 0.428632 0.011353 +vt 0.426256 0.016628 +vt 0.432264 0.025957 +vt 0.426256 0.021733 +vt 0.426256 0.026284 +vt 0.532793 0.827493 +vt 0.531875 0.875894 +vt 0.548738 0.904855 +vt 0.549248 0.882822 +vt 0.532021 0.921485 +vt 0.548738 0.904855 +vt 0.531875 0.875894 +vt 0.510811 0.881395 +vt 0.532021 0.921485 +vt 0.531875 0.875894 +vt 0.510325 0.925896 +vt 0.532021 0.921485 +vt 0.510811 0.881395 +vt 0.640818 0.142998 +vt 0.641504 0.118912 +vt 0.617657 0.145053 +vt 0.641504 0.118912 +vt 0.640818 0.142998 +vt 0.664587 0.141233 +vt 0.640818 0.142998 +vt 0.426550 0.011382 +vt 0.423046 0.016592 +vt 0.424126 0.011353 +vt 0.426502 0.016628 +vt 0.420493 0.025957 +vt 0.426502 0.021733 +vt 0.416448 0.041052 +vt 0.426502 0.026284 +vt 0.426502 0.040793 +vt 0.436309 0.041052 +vt 0.426256 0.040793 +vt 0.426558 0.001523 +vt 0.424130 0.001523 +vt 0.426550 0.011382 +vt 0.642380 0.089071 +vt 0.641504 0.118912 +vt 0.642380 0.089071 +vt 0.426199 0.001523 +vt 0.428627 0.001523 +vt 0.426207 0.011382 +vt 0.579826 0.861468 +vt 0.603688 0.848407 +vt 0.601778 0.116796 +vt 0.575827 0.136910 +vt 0.599397 0.138568 +vt 0.599397 0.138568 +vt 0.575827 0.136910 +vt 0.602669 0.715524 +vt 0.579261 0.722936 +vt 0.579135 0.714707 +vt 0.620328 0.714686 +vt 0.620328 0.764432 +vt 0.429441 0.764432 +vt 0.444010 0.722785 +vt 0.429232 0.714686 +vt 0.444592 0.714807 +vt 0.554455 0.750163 +vt 0.532448 0.768411 +vt 0.455318 0.731023 +vt 0.455648 0.720402 +vt 0.557007 0.658329 +vt 0.578919 0.652931 +vt 0.555031 0.731150 +vt 0.534482 0.661936 +vt 0.534383 0.740525 +vt 0.512759 0.669568 +vt 0.510756 0.742374 +vt 0.495371 0.665965 +vt 0.493674 0.736563 +vt 0.481450 0.662773 +vt 0.480700 0.728624 +vt 0.468151 0.658944 +vt 0.468904 0.724181 +vt 0.456019 0.657282 +vt 0.601618 0.653086 +vt 0.620328 0.655334 +vt 0.443289 0.654584 +vt 0.427565 0.655334 +vt 0.556028 0.577991 +vt 0.551367 0.502011 +vt 0.566101 0.498200 +vt 0.535940 0.502427 +vt 0.535240 0.586430 +vt 0.516860 0.510893 +vt 0.514017 0.598439 +vt 0.498110 0.517702 +vt 0.496643 0.613303 +vt 0.482476 0.612494 +vt 0.480745 0.640869 +vt 0.469022 0.639645 +vt 0.493914 0.640198 +vt 0.513704 0.617600 +vt 0.533953 0.616475 +vt 0.557455 0.614272 +vt 0.620328 0.591948 +vt 0.597884 0.502100 +vt 0.620328 0.507532 +vt 0.599444 0.583034 +vt 0.620328 0.610461 +vt 0.600884 0.609406 +vt 0.620328 0.627708 +vt 0.600364 0.628591 +vt 0.580599 0.501772 +vt 0.576830 0.576687 +vt 0.577087 0.612369 +vt 0.577404 0.633226 +vt 0.557794 0.635372 +vt 0.482143 0.524840 +vt 0.469144 0.610716 +vt 0.457479 0.638655 +vt 0.470124 0.528923 +vt 0.456288 0.610707 +vt 0.445008 0.633020 +vt 0.512910 0.638265 +vt 0.536066 0.635909 +vt 0.427733 0.627708 +vt 0.442740 0.606511 +vt 0.427073 0.610461 +vt 0.426810 0.591948 +vt 0.457631 0.524679 +vt 0.443618 0.517508 +vt 0.423730 0.507532 +vt 0.426256 0.277572 +vt 0.447836 0.311025 +vt 0.453144 0.280467 +vt 0.426256 0.309824 +vt 0.447836 0.311025 +vt 0.426256 0.338561 +vt 0.447836 0.311025 +vt 0.446322 0.338996 +vt 0.447836 0.311025 +vt 0.426256 0.357672 +vt 0.445916 0.362586 +vt 0.617467 0.330827 +vt 0.645717 0.294420 +vt 0.617302 0.291098 +vt 0.644326 0.328181 +vt 0.643843 0.367571 +vt 0.664587 0.330014 +vt 0.664587 0.371398 +vt 0.643843 0.367571 +vt 0.645717 0.294420 +vt 0.617467 0.330827 +vt 0.617302 0.291098 +vt 0.644326 0.328181 +vt 0.617467 0.330827 +vt 0.645717 0.294420 +vt 0.664587 0.294403 +vt 0.644326 0.328181 +vt 0.645717 0.294420 +vt 0.644326 0.328181 +vt 0.459285 0.324689 +vt 0.446322 0.338996 +vt 0.446322 0.338996 +vt 0.446322 0.338996 +vt 0.454450 0.370942 +vt 0.455797 0.336646 +vt 0.459285 0.324689 +vt 0.505772 0.300700 +vt 0.488521 0.324298 +vt 0.491183 0.352112 +vt 0.479491 0.288208 +vt 0.488521 0.324298 +vt 0.505772 0.300700 +vt 0.491183 0.352112 +vt 0.479491 0.288208 +vt 0.505772 0.300700 +vt 0.488521 0.324298 +vt 0.644326 0.328181 +vt 0.643843 0.367571 +vt 0.617467 0.330827 +vt 0.643843 0.367571 +vt 0.644326 0.328181 +vt 0.453144 0.280467 +vt 0.447836 0.311025 +vt 0.459285 0.324689 +vt 0.447836 0.311025 +vt 0.453144 0.280467 +vt 0.445916 0.362586 +vt 0.446322 0.338996 +vt 0.454450 0.370942 +vt 0.446322 0.338996 +vt 0.445916 0.362586 +vt 0.455797 0.336646 +vt 0.446322 0.338996 +vt 0.454450 0.370942 +vt 0.446322 0.338996 +vt 0.455797 0.336646 +vt 0.447836 0.311025 +vt 0.459285 0.324689 +vt 0.654860 0.613698 +vt 0.658236 0.603198 +vt 0.658205 0.616364 +vt 0.654860 0.584706 +vt 0.630435 0.584706 +vt 0.654860 0.556885 +vt 0.630435 0.556885 +vt 0.654860 0.521901 +vt 0.630435 0.497551 +vt 0.646967 0.447095 +vt 0.627185 0.429646 +vt 0.657034 0.565919 +vt 0.656047 0.574804 +vt 0.658009 0.553646 +vt 0.658009 0.521973 +vt 0.664587 0.468097 +vt 0.666363 0.473172 +vt 0.658009 0.521973 +vt 0.654860 0.653915 +vt 0.658895 0.630132 +vt 0.658157 0.643588 +vt 0.654860 0.624846 +vt 0.630436 0.653915 +vt 0.630435 0.613698 +vt 0.624386 0.611649 +vt 0.624386 0.584706 +vt 0.624386 0.556885 +vt 0.630436 0.712033 +vt 0.624386 0.653915 +vt 0.624386 0.712334 +vt 0.630436 0.653915 +vt 0.654860 0.712033 +vt 0.630436 0.653915 +vt 0.654860 0.653915 +vt 0.630436 0.653915 +vt 0.658289 0.683567 +vt 0.654860 0.653915 +vt 0.661602 0.647063 +vt 0.654860 0.653915 +vt 0.630436 0.653915 +vt 0.624386 0.611649 +vt 0.630435 0.613698 +vt 0.624386 0.611649 +vt 0.630436 0.653915 +vt 0.654860 0.624846 +vt 0.630435 0.613698 +vt 0.630436 0.653915 +vt 0.654860 0.613698 +vt 0.630435 0.613698 +vt 0.654860 0.624846 +vt 0.658205 0.616364 +vt 0.654860 0.613698 +vt 0.654860 0.624846 +vt 0.658236 0.603198 +vt 0.654860 0.613698 +vt 0.658205 0.616364 +vt 0.630435 0.613698 +vt 0.624386 0.584706 +vt 0.624386 0.611649 +vt 0.630435 0.584706 +vt 0.624386 0.584706 +vt 0.630435 0.613698 +vt 0.654860 0.613698 +vt 0.630435 0.584706 +vt 0.630435 0.613698 +vt 0.654860 0.584706 +vt 0.630435 0.584706 +vt 0.654860 0.613698 +vt 0.658236 0.603198 +vt 0.654860 0.584706 +vt 0.654860 0.613698 +vt 0.656047 0.574804 +vt 0.654860 0.584706 +vt 0.658236 0.603198 +vt 0.630435 0.584706 +vt 0.624386 0.556885 +vt 0.624386 0.584706 +vt 0.630435 0.556885 +vt 0.624386 0.556885 +vt 0.630435 0.584706 +vt 0.654860 0.556885 +vt 0.630435 0.556885 +vt 0.630435 0.584706 +vt 0.654860 0.521901 +vt 0.630435 0.556885 +vt 0.654860 0.556885 +vt 0.658009 0.553646 +vt 0.654860 0.521901 +vt 0.654860 0.556885 +vt 0.658009 0.521973 +vt 0.654860 0.521901 +vt 0.658009 0.553646 +vt 0.654860 0.712033 +vt 0.660908 0.697975 +vt 0.659624 0.719670 +vt 0.658289 0.683567 +vt 0.654860 0.712033 +vt 0.658289 0.683567 +vt 0.654860 0.712033 +vt 0.661602 0.647063 +vt 0.658289 0.683567 +vt 0.661602 0.647063 +vt 0.630435 0.556885 +vt 0.624386 0.495696 +vt 0.624386 0.556885 +vt 0.630435 0.497551 +vt 0.630435 0.556885 +vt 0.654860 0.521901 +vt 0.630435 0.497551 +vt 0.630435 0.556885 +vt 0.646967 0.447095 +vt 0.630435 0.497551 +vt 0.654860 0.521901 +vt 0.654860 0.624846 +vt 0.658895 0.630132 +vt 0.658205 0.616364 +vt 0.654860 0.653915 +vt 0.658895 0.630132 +vt 0.654860 0.624846 +vt 0.630436 0.653915 +vt 0.654860 0.653915 +vt 0.654860 0.624846 +vt 0.654860 0.556885 +vt 0.657034 0.565919 +vt 0.658009 0.553646 +vt 0.656047 0.574804 +vt 0.657034 0.565919 +vt 0.654860 0.556885 +vt 0.654860 0.584706 +vt 0.656047 0.574804 +vt 0.654860 0.556885 +vt 0.660908 0.697975 +vt 0.659624 0.719670 +vt 0.660908 0.697975 +vt 0.654860 0.712033 +vt 0.630436 0.712033 +vt 0.654860 0.712033 +vt 0.624386 0.495696 +vt 0.624386 0.653915 +vt 0.630436 0.712033 +vt 0.624386 0.653915 +vt 0.624386 0.495696 +vt 0.621152 0.425240 +vt 0.624386 0.495696 +vt 0.658157 0.643588 +vt 0.654860 0.653915 +vt 0.658895 0.630132 +vt 0.654860 0.653915 +vt 0.658157 0.643588 +vt 0.654860 0.521901 +vt 0.658009 0.521973 +vt 0.646967 0.447095 +vt 0.654860 0.521901 +vt 0.627185 0.429646 +vt 0.630435 0.497551 +vt 0.646967 0.447095 +vt 0.621152 0.425240 +vt 0.630435 0.497551 +vt 0.627185 0.429646 +vt 0.630435 0.584706 +vt 0.654860 0.584706 +vt 0.654860 0.556885 +vt 0.621152 0.425240 +vt 0.630435 0.497551 +vt 0.624386 0.712334 +vt 0.624386 0.653915 +vt 0.630436 0.712033 +vt 0.654860 0.796609 +vt 0.660908 0.794439 +vt 0.659269 0.799916 +vt 0.654860 0.750507 +vt 0.654860 0.712033 +vt 0.630436 0.712033 +vt 0.654860 0.712033 +vt 0.630436 0.750507 +vt 0.624386 0.796657 +vt 0.654860 0.750507 +vt 0.654860 0.750507 +vt 0.659624 0.719670 +vt 0.654860 0.750507 +vt 0.615653 0.962304 +vt 0.606905 0.942432 +vt 0.606905 0.962304 +vt 0.615653 0.942432 +vt 0.630807 0.962304 +vt 0.630807 0.942432 +vt 0.630436 0.796609 +vt 0.630436 0.750507 +vt 0.624386 0.796657 +vt 0.630436 0.750507 +vt 0.624386 0.712334 +vt 0.630436 0.750507 +vt 0.624386 0.796657 +vt 0.654860 0.750507 +vt 0.654860 0.796609 +vt 0.659624 0.719670 +vt 0.630436 0.796609 +vt 0.654860 0.796609 +vt 0.654860 0.750507 +vt 0.630436 0.796609 +vt 0.654860 0.750507 +vt 0.630436 0.796609 +vt 0.611550 0.357137 +vt 0.597849 0.306938 +vt 0.595604 0.330836 +vt 0.646967 0.447095 +vt 0.643843 0.367571 +vt 0.611550 0.357137 +vt 0.643843 0.367571 +vt 0.617467 0.330827 +vt 0.643843 0.367571 +vt 0.611550 0.357137 +vt 0.597849 0.306938 +vt 0.617467 0.330827 +vt 0.611550 0.357137 +vt 0.606905 0.942432 +vt 0.615653 0.962304 +vt 0.606905 0.962304 +vt 0.615653 0.942432 +vt 0.615653 0.962304 +vt 0.606905 0.942432 +vt 0.630807 0.962304 +vt 0.615653 0.942432 +vt 0.630807 0.942432 +vt 0.615653 0.962304 +vt 0.615653 0.942432 +vt 0.630807 0.962304 +vt 0.627185 0.429646 +vt 0.646967 0.447095 +vt 0.627185 0.429646 +vt 0.643843 0.367571 +vt 0.643843 0.367571 +vt 0.660908 0.794439 +vt 0.654860 0.796609 +vt 0.659269 0.799916 +vt 0.659624 0.719670 +vt 0.654860 0.796609 +vt 0.660908 0.794439 +vt 0.630436 0.712033 +vt 0.630436 0.750507 +vt 0.624386 0.712334 +vt 0.630436 0.750507 +vt 0.630436 0.712033 +vt 0.611550 0.357137 +vt 0.595604 0.330836 +vt 0.597849 0.306938 +vt 0.457001 0.818480 +vt 0.455335 0.777109 +vt 0.451416 0.805291 +vt 0.468484 0.794278 +vt 0.455335 0.777109 +vt 0.457001 0.818480 +vt 0.467201 0.836968 +vt 0.468484 0.794278 +vt 0.457001 0.818480 +vt 0.478914 0.852812 +vt 0.468484 0.794278 +vt 0.467201 0.836968 +vt 0.477766 0.895439 +vt 0.478914 0.852812 +vt 0.467201 0.836968 +vt 0.617119 0.092642 +vt 0.642380 0.089071 +vt 0.643979 0.064316 +vt 0.616946 0.118228 +vt 0.642380 0.089071 +vt 0.617119 0.092642 +vt 0.601778 0.116796 +vt 0.616946 0.118228 +vt 0.617119 0.092642 +vt 0.616946 0.118228 +vt 0.601778 0.116796 +vt 0.468484 0.794278 +vt 0.481700 0.753131 +vt 0.468723 0.742404 +vt 0.480518 0.809914 +vt 0.481700 0.753131 +vt 0.468484 0.794278 +vt 0.478914 0.852812 +vt 0.480518 0.809914 +vt 0.468484 0.794278 +vt 0.493354 0.823966 +vt 0.480518 0.809914 +vt 0.478914 0.852812 +vt 0.441073 0.792773 +vt 0.455335 0.777109 +vt 0.444007 0.765678 +vt 0.451416 0.805291 +vt 0.455335 0.777109 +vt 0.441073 0.792773 +vt 0.447684 0.836792 +vt 0.451416 0.805291 +vt 0.441073 0.792773 +vt 0.457119 0.857447 +vt 0.451416 0.805291 +vt 0.447684 0.836792 +vt 0.457119 0.857447 +vt 0.457001 0.818480 +vt 0.451416 0.805291 +vt 0.467201 0.836968 +vt 0.457001 0.818480 +vt 0.457119 0.857447 +vt 0.465849 0.876372 +vt 0.467201 0.836968 +vt 0.457119 0.857447 +vt 0.477766 0.895439 +vt 0.467201 0.836968 +vt 0.465849 0.876372 +vt 0.643979 0.064316 +vt 0.643979 0.064316 +vt 0.642380 0.089071 +vt 0.643979 0.064316 +vt 0.616946 0.118228 +vt 0.641504 0.118912 +vt 0.642380 0.089071 +vt 0.617657 0.145053 +vt 0.641504 0.118912 +vt 0.616946 0.118228 +vt 0.617657 0.145053 +vt 0.616946 0.118228 +vt 0.599397 0.138568 +vt 0.599397 0.138568 +vt 0.480518 0.809914 +vt 0.494176 0.764702 +vt 0.481700 0.753131 +vt 0.493354 0.823966 +vt 0.494176 0.764702 +vt 0.480518 0.809914 +vt 0.510135 0.771381 +vt 0.493354 0.823966 +vt 0.510114 0.832468 +vt 0.494176 0.764702 +vt 0.493354 0.823966 +vt 0.510135 0.771381 +vt 0.433923 0.792959 +vt 0.441073 0.792773 +vt 0.444007 0.765678 +vt 0.438208 0.819515 +vt 0.441073 0.792773 +vt 0.433923 0.792959 +vt 0.579805 0.820201 +vt 0.579826 0.861468 +vt 0.549248 0.882822 +vt 0.548738 0.904855 +vt 0.558035 0.884887 +vt 0.438208 0.819515 +vt 0.447684 0.836792 +vt 0.441073 0.792773 +vt 0.491231 0.913030 +vt 0.478914 0.852812 +vt 0.477766 0.895439 +vt 0.494364 0.871486 +vt 0.478914 0.852812 +vt 0.491231 0.913030 +vt 0.510325 0.925896 +vt 0.494364 0.871486 +vt 0.491231 0.913030 +vt 0.510811 0.881395 +vt 0.494364 0.871486 +vt 0.510325 0.925896 +vt 0.531875 0.875894 +vt 0.532793 0.827493 +vt 0.510114 0.832468 +vt 0.549759 0.856100 +vt 0.532793 0.827493 +vt 0.531875 0.875894 +vt 0.549248 0.882822 +vt 0.549759 0.856100 +vt 0.531875 0.875894 +vt 0.558035 0.884887 +vt 0.549759 0.856100 +vt 0.549248 0.882822 +vt 0.549759 0.856100 +vt 0.554455 0.804074 +vt 0.532793 0.827493 +vt 0.556350 0.845199 +vt 0.554455 0.804074 +vt 0.549759 0.856100 +vt 0.558035 0.884887 +vt 0.556350 0.845199 +vt 0.549759 0.856100 +vt 0.579826 0.861468 +vt 0.556350 0.845199 +vt 0.558035 0.884887 +vt 0.579805 0.820201 +vt 0.556350 0.845199 +vt 0.579826 0.861468 +vt 0.554455 0.804074 +vt 0.556350 0.845199 +vt 0.579805 0.820201 +vt 0.579652 0.771697 +vt 0.554455 0.804074 +vt 0.579805 0.820201 +vt 0.592683 0.808109 +vt 0.579805 0.820201 +vt 0.579652 0.771697 +vt 0.579805 0.820201 +vt 0.592683 0.808109 +vt 0.603602 0.767589 +vt 0.579652 0.771697 +vt 0.592683 0.808109 +vt 0.494364 0.871486 +vt 0.493354 0.823966 +vt 0.478914 0.852812 +vt 0.510811 0.881395 +vt 0.493354 0.823966 +vt 0.494364 0.871486 +vt 0.510811 0.881395 +vt 0.510114 0.832468 +vt 0.493354 0.823966 +vt 0.531875 0.875894 +vt 0.510114 0.832468 +vt 0.510811 0.881395 +vt 0.592683 0.808109 +vt 0.603602 0.767589 +vt 0.592683 0.808109 +vt 0.512200 0.142215 +vt 0.510795 0.173040 +vt 0.483443 0.118602 +vt 0.541581 0.192579 +vt 0.544057 0.160295 +vt 0.571578 0.198787 +vt 0.573109 0.163016 +vt 0.595105 0.205690 +vt 0.597213 0.165569 +vt 0.400708 0.182469 +vt 0.426502 0.120204 +vt 0.426502 0.176801 +vt 0.403026 0.125500 +vt 0.369229 0.202332 +vt 0.368786 0.154471 +vt 0.343845 0.220005 +vt 0.341962 0.173040 +vt 0.540475 0.233672 +vt 0.570669 0.241278 +vt 0.508912 0.220005 +vt 0.483972 0.154471 +vt 0.426256 0.120204 +vt 0.452050 0.182469 +vt 0.426256 0.176801 +vt 0.449732 0.125500 +vt 0.438537 0.084980 +vt 0.454739 0.093179 +vt 0.483528 0.202332 +vt 0.571578 0.198787 +vt 0.540475 0.233672 +vt 0.570669 0.241278 +vt 0.541581 0.192579 +vt 0.540475 0.233672 +vt 0.571578 0.198787 +vt 0.544057 0.160295 +vt 0.541581 0.192579 +vt 0.571578 0.198787 +vt 0.512200 0.142215 +vt 0.541581 0.192579 +vt 0.544057 0.160295 +vt 0.369314 0.118602 +vt 0.340557 0.142215 +vt 0.398018 0.093179 +vt 0.541581 0.192579 +vt 0.508912 0.220005 +vt 0.540475 0.233672 +vt 0.510795 0.173040 +vt 0.508912 0.220005 +vt 0.541581 0.192579 +vt 0.512200 0.142215 +vt 0.510795 0.173040 +vt 0.541581 0.192579 +vt 0.573109 0.163016 +vt 0.595105 0.205690 +vt 0.597213 0.165569 +vt 0.571578 0.198787 +vt 0.595105 0.205690 +vt 0.573109 0.163016 +vt 0.544057 0.160295 +vt 0.571578 0.198787 +vt 0.573109 0.163016 +vt 0.414220 0.084980 +vt 0.426502 0.078784 +vt 0.426256 0.078784 +vt 0.599397 0.138568 +vt 0.575827 0.136910 +vt 0.599397 0.138568 +vt 0.575827 0.136910 +vt 0.546655 0.142246 +vt 0.575827 0.136910 +vt 0.513915 0.126683 +vt 0.485918 0.105406 +vt 0.456451 0.082344 +vt 0.442995 0.059452 +vt 0.616668 0.212044 +vt 0.597213 0.165569 +vt 0.595105 0.205690 +vt 0.617507 0.172324 +vt 0.597213 0.165569 +vt 0.642124 0.216241 +vt 0.640934 0.174406 +vt 0.664587 0.169053 +vt 0.640934 0.174406 +vt 0.640934 0.174406 +vt 0.640934 0.174406 +vt 0.544057 0.160295 +vt 0.513915 0.126683 +vt 0.512200 0.142215 +vt 0.546655 0.142246 +vt 0.513915 0.126683 +vt 0.544057 0.160295 +vt 0.573109 0.163016 +vt 0.546655 0.142246 +vt 0.544057 0.160295 +vt 0.546655 0.142246 +vt 0.573109 0.163016 +vt 0.597213 0.165569 +vt 0.573109 0.163016 +vt 0.597213 0.165569 +vt 0.617657 0.145053 +vt 0.597213 0.165569 +vt 0.409762 0.059452 +vt 0.396307 0.082344 +vt 0.366840 0.105406 +vt 0.338842 0.126683 +vt 0.616668 0.212044 +vt 0.617507 0.172324 +vt 0.616668 0.212044 +vt 0.617507 0.172324 +vt 0.640934 0.174406 +vt 0.617507 0.172324 +vt 0.617657 0.145053 +vt 0.597213 0.165569 +vt 0.617657 0.145053 +vt 0.640818 0.142998 +vt 0.617657 0.145053 +vt 0.640818 0.142998 +vt 0.617507 0.172324 +vt 0.642124 0.216241 +vt 0.616668 0.212044 +vt 0.640934 0.174406 +vt 0.642124 0.216241 +vt 0.617507 0.172324 +vt 0.664587 0.209935 +vt 0.642124 0.216241 +vt 0.642124 0.216241 +vt 0.640934 0.174406 +vt 0.444007 0.765678 +vt 0.429441 0.764432 +vt 0.433923 0.792959 +vt 0.444010 0.722785 +vt 0.429441 0.764432 +vt 0.444007 0.765678 +vt 0.455318 0.731023 +vt 0.444010 0.722785 +vt 0.444007 0.765678 +vt 0.579261 0.722936 +vt 0.602669 0.715524 +vt 0.579135 0.714707 +vt 0.603602 0.767589 +vt 0.602669 0.715524 +vt 0.579261 0.722936 +vt 0.579652 0.771697 +vt 0.603602 0.767589 +vt 0.579261 0.722936 +vt 0.455335 0.777109 +vt 0.455318 0.731023 +vt 0.444007 0.765678 +vt 0.468723 0.742404 +vt 0.455318 0.731023 +vt 0.455335 0.777109 +vt 0.468484 0.794278 +vt 0.468723 0.742404 +vt 0.455335 0.777109 +vt 0.554455 0.750163 +vt 0.579652 0.771697 +vt 0.579261 0.722936 +vt 0.554455 0.804074 +vt 0.579652 0.771697 +vt 0.554455 0.750163 +vt 0.620328 0.714686 +vt 0.603602 0.767589 +vt 0.620328 0.764432 +vt 0.602669 0.715524 +vt 0.603602 0.767589 +vt 0.620328 0.714686 +vt 0.429232 0.714686 +vt 0.429441 0.764432 +vt 0.444010 0.722785 +vt 0.493674 0.736563 +vt 0.510135 0.771381 +vt 0.510756 0.742374 +vt 0.494176 0.764702 +vt 0.510135 0.771381 +vt 0.493674 0.736563 +vt 0.480700 0.728624 +vt 0.494176 0.764702 +vt 0.493674 0.736563 +vt 0.481700 0.753131 +vt 0.494176 0.764702 +vt 0.480700 0.728624 +vt 0.468904 0.724181 +vt 0.481700 0.753131 +vt 0.480700 0.728624 +vt 0.468723 0.742404 +vt 0.481700 0.753131 +vt 0.468904 0.724181 +vt 0.455648 0.720402 +vt 0.468723 0.742404 +vt 0.468904 0.724181 +vt 0.456019 0.657282 +vt 0.468904 0.724181 +vt 0.468151 0.658944 +vt 0.455648 0.720402 +vt 0.468904 0.724181 +vt 0.456019 0.657282 +vt 0.443289 0.654584 +vt 0.455648 0.720402 +vt 0.456019 0.657282 +vt 0.444592 0.714807 +vt 0.455648 0.720402 +vt 0.443289 0.654584 +vt 0.427565 0.655334 +vt 0.444592 0.714807 +vt 0.443289 0.654584 +vt 0.429232 0.714686 +vt 0.444592 0.714807 +vt 0.427565 0.655334 +vt 0.532448 0.768411 +vt 0.554455 0.804074 +vt 0.554455 0.750163 +vt 0.532793 0.827493 +vt 0.554455 0.804074 +vt 0.532448 0.768411 +vt 0.510114 0.832468 +vt 0.532793 0.827493 +vt 0.532448 0.768411 +vt 0.532448 0.768411 +vt 0.510135 0.771381 +vt 0.510114 0.832468 +vt 0.510756 0.742374 +vt 0.510135 0.771381 +vt 0.532448 0.768411 +vt 0.534383 0.740525 +vt 0.510756 0.742374 +vt 0.532448 0.768411 +vt 0.444010 0.722785 +vt 0.444592 0.714807 +vt 0.429232 0.714686 +vt 0.455318 0.731023 +vt 0.444592 0.714807 +vt 0.444010 0.722785 +vt 0.455318 0.731023 +vt 0.455648 0.720402 +vt 0.444592 0.714807 +vt 0.468723 0.742404 +vt 0.455648 0.720402 +vt 0.455318 0.731023 +vt 0.555031 0.731150 +vt 0.534482 0.661936 +vt 0.534383 0.740525 +vt 0.557007 0.658329 +vt 0.534482 0.661936 +vt 0.555031 0.731150 +vt 0.579135 0.714707 +vt 0.557007 0.658329 +vt 0.555031 0.731150 +vt 0.578919 0.652931 +vt 0.557007 0.658329 +vt 0.579135 0.714707 +vt 0.602669 0.715524 +vt 0.578919 0.652931 +vt 0.579135 0.714707 +vt 0.601618 0.653086 +vt 0.578919 0.652931 +vt 0.602669 0.715524 +vt 0.620328 0.714686 +vt 0.601618 0.653086 +vt 0.602669 0.715524 +vt 0.620328 0.655334 +vt 0.601618 0.653086 +vt 0.620328 0.714686 +vt 0.554455 0.750163 +vt 0.534383 0.740525 +vt 0.532448 0.768411 +vt 0.555031 0.731150 +vt 0.534383 0.740525 +vt 0.554455 0.750163 +vt 0.579261 0.722936 +vt 0.555031 0.731150 +vt 0.554455 0.750163 +vt 0.579135 0.714707 +vt 0.555031 0.731150 +vt 0.579261 0.722936 +vt 0.601618 0.653086 +vt 0.577404 0.633226 +vt 0.578919 0.652931 +vt 0.600364 0.628591 +vt 0.577404 0.633226 +vt 0.601618 0.653086 +vt 0.620328 0.655334 +vt 0.600364 0.628591 +vt 0.601618 0.653086 +vt 0.620328 0.627708 +vt 0.600364 0.628591 +vt 0.620328 0.655334 +vt 0.512759 0.669568 +vt 0.536066 0.635909 +vt 0.512910 0.638265 +vt 0.534482 0.661936 +vt 0.536066 0.635909 +vt 0.512759 0.669568 +vt 0.536066 0.635909 +vt 0.557007 0.658329 +vt 0.557794 0.635372 +vt 0.534482 0.661936 +vt 0.557007 0.658329 +vt 0.536066 0.635909 +vt 0.599444 0.583034 +vt 0.620328 0.610461 +vt 0.620328 0.591948 +vt 0.600884 0.609406 +vt 0.620328 0.610461 +vt 0.599444 0.583034 +vt 0.576830 0.576687 +vt 0.600884 0.609406 +vt 0.599444 0.583034 +vt 0.577087 0.612369 +vt 0.600884 0.609406 +vt 0.576830 0.576687 +vt 0.556028 0.577991 +vt 0.577087 0.612369 +vt 0.576830 0.576687 +vt 0.557455 0.614272 +vt 0.577087 0.612369 +vt 0.556028 0.577991 +vt 0.535240 0.586430 +vt 0.557455 0.614272 +vt 0.556028 0.577991 +vt 0.533953 0.616475 +vt 0.557455 0.614272 +vt 0.535240 0.586430 +vt 0.514017 0.598439 +vt 0.533953 0.616475 +vt 0.535240 0.586430 +vt 0.513704 0.617600 +vt 0.533953 0.616475 +vt 0.514017 0.598439 +vt 0.600884 0.609406 +vt 0.620328 0.627708 +vt 0.620328 0.610461 +vt 0.600364 0.628591 +vt 0.620328 0.627708 +vt 0.600884 0.609406 +vt 0.577087 0.612369 +vt 0.600364 0.628591 +vt 0.600884 0.609406 +vt 0.577404 0.633226 +vt 0.600364 0.628591 +vt 0.577087 0.612369 +vt 0.557455 0.614272 +vt 0.577404 0.633226 +vt 0.577087 0.612369 +vt 0.557794 0.635372 +vt 0.577404 0.633226 +vt 0.557455 0.614272 +vt 0.533953 0.616475 +vt 0.557794 0.635372 +vt 0.557455 0.614272 +vt 0.536066 0.635909 +vt 0.557794 0.635372 +vt 0.533953 0.616475 +vt 0.512910 0.638265 +vt 0.536066 0.635909 +vt 0.533953 0.616475 +vt 0.480700 0.728624 +vt 0.468151 0.658944 +vt 0.468904 0.724181 +vt 0.481450 0.662773 +vt 0.468151 0.658944 +vt 0.480700 0.728624 +vt 0.493674 0.736563 +vt 0.481450 0.662773 +vt 0.480700 0.728624 +vt 0.495371 0.665965 +vt 0.481450 0.662773 +vt 0.493674 0.736563 +vt 0.510756 0.742374 +vt 0.495371 0.665965 +vt 0.493674 0.736563 +vt 0.512759 0.669568 +vt 0.495371 0.665965 +vt 0.510756 0.742374 +vt 0.534383 0.740525 +vt 0.512759 0.669568 +vt 0.510756 0.742374 +vt 0.534482 0.661936 +vt 0.512759 0.669568 +vt 0.534383 0.740525 +vt 0.597884 0.502100 +vt 0.620328 0.591948 +vt 0.620328 0.507532 +vt 0.599444 0.583034 +vt 0.620328 0.591948 +vt 0.597884 0.502100 +vt 0.580599 0.501772 +vt 0.599444 0.583034 +vt 0.597884 0.502100 +vt 0.576830 0.576687 +vt 0.599444 0.583034 +vt 0.580599 0.501772 +vt 0.566101 0.498200 +vt 0.576830 0.576687 +vt 0.580599 0.501772 +vt 0.556028 0.577991 +vt 0.576830 0.576687 +vt 0.566101 0.498200 +vt 0.551367 0.502011 +vt 0.556028 0.577991 +vt 0.566101 0.498200 +vt 0.535940 0.502427 +vt 0.556028 0.577991 +vt 0.551367 0.502011 +vt 0.512910 0.638265 +vt 0.495371 0.665965 +vt 0.512759 0.669568 +vt 0.493914 0.640198 +vt 0.495371 0.665965 +vt 0.512910 0.638265 +vt 0.513704 0.617600 +vt 0.493914 0.640198 +vt 0.512910 0.638265 +vt 0.496643 0.613303 +vt 0.493914 0.640198 +vt 0.513704 0.617600 +vt 0.514017 0.598439 +vt 0.496643 0.613303 +vt 0.513704 0.617600 +vt 0.498110 0.517702 +vt 0.496643 0.613303 +vt 0.514017 0.598439 +vt 0.516860 0.510893 +vt 0.498110 0.517702 +vt 0.514017 0.598439 +vt 0.493914 0.640198 +vt 0.481450 0.662773 +vt 0.495371 0.665965 +vt 0.480745 0.640869 +vt 0.481450 0.662773 +vt 0.493914 0.640198 +vt 0.496643 0.613303 +vt 0.480745 0.640869 +vt 0.493914 0.640198 +vt 0.482476 0.612494 +vt 0.480745 0.640869 +vt 0.496643 0.613303 +vt 0.498110 0.517702 +vt 0.482476 0.612494 +vt 0.496643 0.613303 +vt 0.482143 0.524840 +vt 0.482476 0.612494 +vt 0.498110 0.517702 +vt 0.480745 0.640869 +vt 0.468151 0.658944 +vt 0.481450 0.662773 +vt 0.469022 0.639645 +vt 0.468151 0.658944 +vt 0.480745 0.640869 +vt 0.482476 0.612494 +vt 0.469022 0.639645 +vt 0.480745 0.640869 +vt 0.469144 0.610716 +vt 0.469022 0.639645 +vt 0.482476 0.612494 +vt 0.482143 0.524840 +vt 0.469144 0.610716 +vt 0.482476 0.612494 +vt 0.470124 0.528923 +vt 0.469144 0.610716 +vt 0.482143 0.524840 +vt 0.469022 0.639645 +vt 0.456019 0.657282 +vt 0.468151 0.658944 +vt 0.457479 0.638655 +vt 0.456019 0.657282 +vt 0.469022 0.639645 +vt 0.469144 0.610716 +vt 0.457479 0.638655 +vt 0.469022 0.639645 +vt 0.456288 0.610707 +vt 0.457479 0.638655 +vt 0.469144 0.610716 +vt 0.470124 0.528923 +vt 0.456288 0.610707 +vt 0.469144 0.610716 +vt 0.457631 0.524679 +vt 0.456288 0.610707 +vt 0.470124 0.528923 +vt 0.457479 0.638655 +vt 0.443289 0.654584 +vt 0.456019 0.657282 +vt 0.445008 0.633020 +vt 0.443289 0.654584 +vt 0.457479 0.638655 +vt 0.456288 0.610707 +vt 0.445008 0.633020 +vt 0.457479 0.638655 +vt 0.442740 0.606511 +vt 0.445008 0.633020 +vt 0.456288 0.610707 +vt 0.457631 0.524679 +vt 0.442740 0.606511 +vt 0.456288 0.610707 +vt 0.443618 0.517508 +vt 0.442740 0.606511 +vt 0.457631 0.524679 +vt 0.445008 0.633020 +vt 0.427565 0.655334 +vt 0.443289 0.654584 +vt 0.427733 0.627708 +vt 0.427565 0.655334 +vt 0.445008 0.633020 +vt 0.442740 0.606511 +vt 0.427733 0.627708 +vt 0.445008 0.633020 +vt 0.427073 0.610461 +vt 0.427733 0.627708 +vt 0.442740 0.606511 +vt 0.426810 0.591948 +vt 0.427073 0.610461 +vt 0.442740 0.606511 +vt 0.442740 0.606511 +vt 0.423730 0.507532 +vt 0.426810 0.591948 +vt 0.443618 0.517508 +vt 0.423730 0.507532 +vt 0.442740 0.606511 +vt 0.535940 0.502427 +vt 0.535240 0.586430 +vt 0.556028 0.577991 +vt 0.516860 0.510893 +vt 0.535240 0.586430 +vt 0.535940 0.502427 +vt 0.557794 0.635372 +vt 0.578919 0.652931 +vt 0.577404 0.633226 +vt 0.557007 0.658329 +vt 0.578919 0.652931 +vt 0.557794 0.635372 +vt 0.514017 0.598439 +vt 0.535240 0.586430 +vt 0.516860 0.510893 +vt 0.513704 0.617600 +vt 0.512910 0.638265 +vt 0.533953 0.616475 +vt 0.446090 0.445702 +vt 0.422541 0.467178 +vt 0.423631 0.426455 +vt 0.443198 0.481351 +vt 0.458217 0.460229 +vt 0.455570 0.490020 +vt 0.470195 0.468469 +vt 0.470096 0.496915 +vt 0.482251 0.462994 +vt 0.484805 0.492531 +vt 0.496320 0.446794 +vt 0.499606 0.481984 +vt 0.515581 0.429359 +vt 0.517416 0.470969 +vt 0.534437 0.414919 +vt 0.535477 0.462773 +vt 0.549828 0.460347 +vt 0.565723 0.459997 +vt 0.582239 0.459707 +vt 0.551367 0.502011 +vt 0.535477 0.462773 +vt 0.535940 0.502427 +vt 0.549828 0.460347 +vt 0.535477 0.462773 +vt 0.551367 0.502011 +vt 0.565723 0.459997 +vt 0.549828 0.460347 +vt 0.551367 0.502011 +vt 0.565575 0.412763 +vt 0.549828 0.460347 +vt 0.565723 0.459997 +vt 0.582054 0.411298 +vt 0.565723 0.459997 +vt 0.596002 0.461873 +vt 0.596317 0.413613 +vt 0.582239 0.459707 +vt 0.565723 0.459997 +vt 0.582239 0.459707 +vt 0.566101 0.498200 +vt 0.582239 0.459707 +vt 0.565723 0.459997 +vt 0.551367 0.502011 +vt 0.566101 0.498200 +vt 0.565723 0.459997 +vt 0.422541 0.467178 +vt 0.446090 0.445702 +vt 0.423631 0.426455 +vt 0.443198 0.481351 +vt 0.446090 0.445702 +vt 0.422541 0.467178 +vt 0.423730 0.507532 +vt 0.443198 0.481351 +vt 0.422541 0.467178 +vt 0.443618 0.517508 +vt 0.443198 0.481351 +vt 0.423730 0.507532 +vt 0.443198 0.481351 +vt 0.458217 0.460229 +vt 0.446090 0.445702 +vt 0.455570 0.490020 +vt 0.458217 0.460229 +vt 0.443198 0.481351 +vt 0.443618 0.517508 +vt 0.455570 0.490020 +vt 0.443198 0.481351 +vt 0.457631 0.524679 +vt 0.455570 0.490020 +vt 0.443618 0.517508 +vt 0.455570 0.490020 +vt 0.470195 0.468469 +vt 0.458217 0.460229 +vt 0.470096 0.496915 +vt 0.470195 0.468469 +vt 0.455570 0.490020 +vt 0.457631 0.524679 +vt 0.470096 0.496915 +vt 0.455570 0.490020 +vt 0.470124 0.528923 +vt 0.470096 0.496915 +vt 0.457631 0.524679 +vt 0.470096 0.496915 +vt 0.482251 0.462994 +vt 0.470195 0.468469 +vt 0.484805 0.492531 +vt 0.482251 0.462994 +vt 0.470096 0.496915 +vt 0.470124 0.528923 +vt 0.484805 0.492531 +vt 0.470096 0.496915 +vt 0.482143 0.524840 +vt 0.484805 0.492531 +vt 0.470124 0.528923 +vt 0.484805 0.492531 +vt 0.496320 0.446794 +vt 0.482251 0.462994 +vt 0.499606 0.481984 +vt 0.496320 0.446794 +vt 0.484805 0.492531 +vt 0.482143 0.524840 +vt 0.499606 0.481984 +vt 0.484805 0.492531 +vt 0.498110 0.517702 +vt 0.499606 0.481984 +vt 0.482143 0.524840 +vt 0.499606 0.481984 +vt 0.515581 0.429359 +vt 0.496320 0.446794 +vt 0.517416 0.470969 +vt 0.515581 0.429359 +vt 0.499606 0.481984 +vt 0.498110 0.517702 +vt 0.517416 0.470969 +vt 0.499606 0.481984 +vt 0.516860 0.510893 +vt 0.517416 0.470969 +vt 0.498110 0.517702 +vt 0.517416 0.470969 +vt 0.534437 0.414919 +vt 0.515581 0.429359 +vt 0.535477 0.462773 +vt 0.534437 0.414919 +vt 0.517416 0.470969 +vt 0.516860 0.510893 +vt 0.535477 0.462773 +vt 0.517416 0.470969 +vt 0.535940 0.502427 +vt 0.535477 0.462773 +vt 0.516860 0.510893 +vt 0.620328 0.467178 +vt 0.597884 0.502100 +vt 0.620328 0.507532 +vt 0.597884 0.502100 +vt 0.620328 0.426455 +vt 0.582054 0.411298 +vt 0.596002 0.461873 +vt 0.582054 0.411298 +vt 0.596317 0.413613 +vt 0.596002 0.461873 +vt 0.582054 0.411298 +vt 0.620328 0.426455 +vt 0.596002 0.461873 +vt 0.596317 0.413613 +vt 0.620328 0.467178 +vt 0.596002 0.461873 +vt 0.620328 0.426455 +vt 0.596002 0.461873 +vt 0.620328 0.467178 +vt 0.620328 0.467178 +vt 0.468434 0.384538 +vt 0.479850 0.384369 +vt 0.477465 0.405845 +vt 0.478959 0.361184 +vt 0.475594 0.341355 +vt 0.468434 0.332407 +vt 0.475594 0.341355 +vt 0.478959 0.361184 +vt 0.475594 0.341355 +vt 0.468434 0.384538 +vt 0.475594 0.341355 +vt 0.478959 0.361184 +vt 0.468434 0.332407 +vt 0.475594 0.341355 +vt 0.468434 0.384538 +vt 0.475594 0.341355 +vt 0.468434 0.332407 +vt 0.468434 0.384538 +vt 0.549808 0.412206 +vt 0.549828 0.460347 +vt 0.534437 0.414919 +vt 0.549828 0.460347 +vt 0.580599 0.501772 +vt 0.582239 0.459707 +vt 0.566101 0.498200 +vt 0.597884 0.502100 +vt 0.582239 0.459707 +vt 0.580599 0.501772 +vt 0.549808 0.412206 +vt 0.565575 0.412763 +vt 0.549808 0.412206 +vt 0.565575 0.412763 +vt 0.582054 0.411298 +vt 0.565575 0.412763 +vt 0.473282 0.418990 +vt 0.468434 0.425132 +vt 0.473282 0.418990 +vt 0.477465 0.405845 +vt 0.473282 0.418990 +vt 0.479891 0.384006 +vt 0.478959 0.361184 +vt 0.477465 0.405845 +vt 0.479891 0.384006 +vt 0.468434 0.384538 +vt 0.478959 0.361184 +vt 0.477465 0.405845 +vt 0.468434 0.384538 +vt 0.479891 0.384006 +vt 0.473282 0.418990 +vt 0.468434 0.384538 +vt 0.477465 0.405845 +vt 0.468434 0.425132 +vt 0.468434 0.384538 +vt 0.473282 0.418990 +vt 0.473282 0.418990 +vt 0.468434 0.384538 +vt 0.468434 0.425132 +vt 0.477465 0.405845 +vt 0.468434 0.384538 +vt 0.473282 0.418990 +vt 0.479850 0.384369 +vt 0.468434 0.384538 +vt 0.477465 0.405845 +vt 0.478959 0.361184 +vt 0.468434 0.384538 +vt 0.479850 0.384369 +vt 0.582239 0.459707 +vt 0.597884 0.502100 +vt 0.535477 0.462773 +vt 0.549828 0.460347 +vt 0.534437 0.414919 +vt 0.596002 0.461873 +vt 0.475594 0.341355 +vt 0.468434 0.384538 +vt 0.478959 0.361184 +vt 0.426256 0.233986 +vt 0.453144 0.280467 +vt 0.453886 0.239649 +vt 0.453144 0.280467 +vt 0.479491 0.288208 +vt 0.453144 0.280467 +vt 0.481420 0.254523 +vt 0.479491 0.288208 +vt 0.505772 0.300700 +vt 0.479491 0.288208 +vt 0.507086 0.269863 +vt 0.505772 0.300700 +vt 0.522966 0.290967 +vt 0.505772 0.300700 +vt 0.541952 0.277895 +vt 0.550751 0.304375 +vt 0.573917 0.301305 +vt 0.572347 0.321364 +vt 0.471652 0.297038 +vt 0.453886 0.239649 +vt 0.453886 0.239649 +vt 0.453886 0.239649 +vt 0.630485 0.919398 +vt 0.624386 0.919398 +vt 0.630485 0.941277 +vt 0.624386 0.895871 +vt 0.630485 0.895945 +vt 0.624386 0.884597 +vt 0.630436 0.884597 +vt 0.624386 0.853875 +vt 0.630436 0.853875 +vt 0.624386 0.804517 +vt 0.630436 0.796609 +vt 0.630436 0.796609 +vt 0.570669 0.241278 +vt 0.596584 0.281643 +vt 0.594589 0.246615 +vt 0.572253 0.276883 +vt 0.570669 0.241278 +vt 0.541952 0.277895 +vt 0.570669 0.241278 +vt 0.573917 0.301305 +vt 0.541952 0.277895 +vt 0.550751 0.304375 +vt 0.573917 0.301305 +vt 0.541952 0.277895 +vt 0.572347 0.321364 +vt 0.573917 0.301305 +vt 0.550751 0.304375 +vt 0.553702 0.325976 +vt 0.572347 0.321364 +vt 0.550751 0.304375 +vt 0.481420 0.254523 +vt 0.483528 0.202332 +vt 0.452050 0.182469 +vt 0.507086 0.269863 +vt 0.483528 0.202332 +vt 0.481420 0.254523 +vt 0.507086 0.269863 +vt 0.481420 0.254523 +vt 0.522966 0.290967 +vt 0.507086 0.269863 +vt 0.527686 0.310423 +vt 0.522966 0.290967 +vt 0.550751 0.304375 +vt 0.522966 0.290967 +vt 0.550751 0.304375 +vt 0.596584 0.281643 +vt 0.594589 0.246615 +vt 0.572253 0.276883 +vt 0.596584 0.281643 +vt 0.597849 0.306938 +vt 0.572253 0.276883 +vt 0.596584 0.281643 +vt 0.572253 0.276883 +vt 0.597849 0.306938 +vt 0.595604 0.330836 +vt 0.597849 0.306938 +vt 0.595604 0.330836 +vt 0.624386 0.804517 +vt 0.624386 0.796657 +vt 0.630436 0.853875 +vt 0.624386 0.804517 +vt 0.630436 0.853875 +vt 0.654860 0.853875 +vt 0.630436 0.853875 +vt 0.659269 0.853868 +vt 0.553702 0.325976 +vt 0.527686 0.310423 +vt 0.553702 0.325976 +vt 0.534533 0.330762 +vt 0.527686 0.310423 +vt 0.553702 0.325976 +vt 0.508917 0.322771 +vt 0.527686 0.310423 +vt 0.510266 0.352896 +vt 0.493142 0.396674 +vt 0.654860 0.884597 +vt 0.642552 0.924850 +vt 0.654860 0.853875 +vt 0.654860 0.796609 +vt 0.654860 0.853875 +vt 0.659269 0.799916 +vt 0.654860 0.796609 +vt 0.654860 0.853875 +vt 0.527686 0.310423 +vt 0.505772 0.300700 +vt 0.527686 0.310423 +vt 0.505772 0.300700 +vt 0.527686 0.310423 +vt 0.491183 0.352112 +vt 0.505772 0.300700 +vt 0.491183 0.352112 +vt 0.630436 0.853875 +vt 0.624386 0.853875 +vt 0.624386 0.804517 +vt 0.630436 0.884597 +vt 0.624386 0.853875 +vt 0.630436 0.853875 +vt 0.654860 0.884597 +vt 0.630436 0.884597 +vt 0.630436 0.853875 +vt 0.642552 0.924850 +vt 0.630436 0.884597 +vt 0.654860 0.884597 +vt 0.650343 0.941317 +vt 0.636283 0.961189 +vt 0.636283 0.941317 +vt 0.650343 0.961189 +vt 0.663103 0.941317 +vt 0.663103 0.961189 +vt 0.446075 0.416804 +vt 0.454546 0.423452 +vt 0.426256 0.409778 +vt 0.648516 0.942432 +vt 0.664777 0.962304 +vt 0.664777 0.942432 +vt 0.648516 0.962304 +vt 0.453886 0.239649 +vt 0.452050 0.182469 +vt 0.481420 0.254523 +vt 0.452050 0.182469 +vt 0.453886 0.239649 +vt 0.481420 0.254523 +vt 0.453886 0.239649 +vt 0.481420 0.254523 +vt 0.541952 0.277895 +vt 0.522966 0.290967 +vt 0.550751 0.304375 +vt 0.507086 0.269863 +vt 0.522966 0.290967 +vt 0.541952 0.277895 +vt 0.540475 0.233672 +vt 0.507086 0.269863 +vt 0.541952 0.277895 +vt 0.508912 0.220005 +vt 0.507086 0.269863 +vt 0.540475 0.233672 +vt 0.534533 0.330762 +vt 0.508917 0.322771 +vt 0.534533 0.330762 +vt 0.508917 0.322771 +vt 0.508917 0.322771 +vt 0.573917 0.301305 +vt 0.471652 0.297038 +vt 0.479491 0.288208 +vt 0.488521 0.324298 +vt 0.453144 0.280467 +vt 0.479491 0.288208 +vt 0.471652 0.297038 +vt 0.459285 0.324689 +vt 0.453144 0.280467 +vt 0.471652 0.297038 +vt 0.508917 0.322771 +vt 0.510266 0.352896 +vt 0.534533 0.330762 +vt 0.493142 0.396674 +vt 0.510266 0.352896 +vt 0.508917 0.322771 +vt 0.493142 0.396674 +vt 0.508917 0.322771 +vt 0.630807 0.942432 +vt 0.648516 0.962304 +vt 0.630807 0.962304 +vt 0.648516 0.942432 +vt 0.648516 0.962304 +vt 0.630807 0.942432 +vt 0.664347 0.941543 +vt 0.649290 0.961415 +vt 0.664347 0.961415 +vt 0.649290 0.941543 +vt 0.445916 0.362586 +vt 0.446075 0.416804 +vt 0.445916 0.362586 +vt 0.659269 0.884732 +vt 0.654860 0.884597 +vt 0.659269 0.884732 +vt 0.654860 0.853875 +vt 0.659269 0.853868 +vt 0.654860 0.853875 +vt 0.659269 0.884732 +vt 0.624386 0.919398 +vt 0.630485 0.919398 +vt 0.630485 0.941277 +vt 0.624386 0.895871 +vt 0.630485 0.919398 +vt 0.624386 0.919398 +vt 0.612342 0.941543 +vt 0.625237 0.961415 +vt 0.625237 0.941543 +vt 0.612342 0.961415 +vt 0.630436 0.884597 +vt 0.624386 0.884597 +vt 0.624386 0.853875 +vt 0.630485 0.895945 +vt 0.624386 0.884597 +vt 0.630436 0.884597 +vt 0.664393 0.961415 +vt 0.653570 0.941543 +vt 0.653570 0.961415 +vt 0.664393 0.941543 +vt 0.649290 0.961415 +vt 0.664347 0.941543 +vt 0.664347 0.961415 +vt 0.649290 0.941543 +vt 0.664347 0.941543 +vt 0.649290 0.961415 +vt 0.572253 0.276883 +vt 0.572253 0.276883 +vt 0.454450 0.370942 +vt 0.446075 0.416804 +vt 0.454546 0.423452 +vt 0.445916 0.362586 +vt 0.446075 0.416804 +vt 0.454450 0.370942 +vt 0.664777 0.962304 +vt 0.648516 0.942432 +vt 0.664777 0.942432 +vt 0.648516 0.962304 +vt 0.648516 0.942432 +vt 0.664777 0.962304 +vt 0.663103 0.941317 +vt 0.650343 0.961189 +vt 0.663103 0.961189 +vt 0.650343 0.941317 +vt 0.650343 0.961189 +vt 0.663103 0.941317 +vt 0.573917 0.301305 +vt 0.572347 0.321364 +vt 0.573917 0.301305 +vt 0.624386 0.895871 +vt 0.630485 0.895945 +vt 0.630485 0.919398 +vt 0.624386 0.884597 +vt 0.630485 0.895945 +vt 0.624386 0.895871 +vt 0.650343 0.941317 +vt 0.650343 0.961189 +vt 0.650343 0.941317 +vt 0.625237 0.961415 +vt 0.612342 0.941543 +vt 0.625237 0.941543 +vt 0.612342 0.961415 +vt 0.612342 0.941543 +vt 0.625237 0.961415 +vt 0.653570 0.941543 +vt 0.664393 0.961415 +vt 0.653570 0.961415 +vt 0.664393 0.941543 +vt 0.664393 0.961415 +vt 0.653570 0.941543 +vt 0.596584 0.281643 +vt 0.617467 0.330827 +vt 0.597849 0.306938 +vt 0.617302 0.291098 +vt 0.617467 0.330827 +vt 0.596584 0.281643 +vt 0.659269 0.799916 +vt 0.654860 0.853875 +vt 0.659269 0.853868 +vt 0.630436 0.796609 +vt 0.654860 0.796609 +vt 0.654860 0.884597 +vt 0.630436 0.853875 +vt 0.507086 0.269863 +vt 0.508912 0.220005 +vt 0.483528 0.202332 +vt 0.540475 0.233672 +vt 0.541952 0.277895 +vt 0.570669 0.241278 +vt 0.616496 0.252425 +vt 0.644706 0.256471 +vt 0.664587 0.256373 +vt 0.644706 0.256471 +vt 0.642124 0.216241 +vt 0.644706 0.256471 +vt 0.616668 0.212044 +vt 0.642124 0.216241 +vt 0.644706 0.256471 +vt 0.571578 0.198787 +vt 0.570669 0.241278 +vt 0.595105 0.205690 +vt 0.571578 0.198787 +vt 0.595105 0.205690 +vt 0.595105 0.205690 +vt 0.645717 0.294420 +vt 0.644706 0.256471 +vt 0.616496 0.252425 +vt 0.644706 0.256471 +vt 0.645717 0.294420 +vt 0.617302 0.291098 +vt 0.616496 0.252425 +vt 0.645717 0.294420 +vt 0.594589 0.246615 +vt 0.616496 0.252425 +vt 0.617302 0.291098 +vt 0.596584 0.281643 +vt 0.594589 0.246615 +vt 0.617302 0.291098 +vt 0.616496 0.252425 +vt 0.616668 0.212044 +vt 0.644706 0.256471 +vt 0.616668 0.212044 +vt 0.616496 0.252425 +vt 0.594589 0.246615 +vt 0.616496 0.252425 +vt 0.645717 0.294420 +vt 0.594589 0.246615 +vt 0.594589 0.246615 +vt 0.345330 0.899507 +vt 0.339095 0.910081 +vt 0.341032 0.892127 +vt 0.343345 0.927534 +vt 0.360639 0.926249 +vt 0.346122 0.954420 +vt 0.360639 0.926249 +vt 0.352778 0.973484 +vt 0.360639 0.926249 +vt 0.345956 0.977097 +vt 0.352778 0.973484 +vt 0.350682 0.987730 +vt 0.352778 0.973484 +vt 0.352778 0.973484 +vt 0.356131 0.993947 +vt 0.350682 0.987730 +vt 0.361500 0.980122 +vt 0.356131 0.993947 +vt 0.352778 0.973484 +vt 0.360639 0.926249 +vt 0.361500 0.980122 +vt 0.352778 0.973484 +vt 0.370030 0.972687 +vt 0.361500 0.980122 +vt 0.360639 0.926249 +vt 0.376186 0.952870 +vt 0.370030 0.972687 +vt 0.360639 0.926249 +vt 0.377257 0.975165 +vt 0.370030 0.972687 +vt 0.376186 0.952870 +vt 0.380759 0.960802 +vt 0.377257 0.975165 +vt 0.376186 0.952870 +vt 0.376186 0.952870 +vt 0.382860 0.943681 +vt 0.380759 0.960802 +vt 0.378371 0.925378 +vt 0.382860 0.943681 +vt 0.376186 0.952870 +vt 0.360639 0.926249 +vt 0.378371 0.925378 +vt 0.376186 0.952870 +vt 0.375780 0.897365 +vt 0.378371 0.925378 +vt 0.360639 0.926249 +vt 0.368910 0.876776 +vt 0.375780 0.897365 +vt 0.360639 0.926249 +vt 0.376138 0.873873 +vt 0.375780 0.897365 +vt 0.368910 0.876776 +vt 0.361500 0.980122 +vt 0.361862 0.996115 +vt 0.356131 0.993947 +vt 0.367525 0.993289 +vt 0.361862 0.996115 +vt 0.361500 0.980122 +vt 0.370030 0.972687 +vt 0.367525 0.993289 +vt 0.361500 0.980122 +vt 0.372808 0.986422 +vt 0.367525 0.993289 +vt 0.370030 0.972687 +vt 0.377257 0.975165 +vt 0.372808 0.986422 +vt 0.370030 0.972687 +vt 0.378371 0.925378 +vt 0.383673 0.925173 +vt 0.382860 0.943681 +vt 0.382591 0.906491 +vt 0.378371 0.925378 +vt 0.375780 0.897365 +vt 0.378371 0.925378 +vt 0.380056 0.888836 +vt 0.375780 0.897365 +vt 0.376138 0.873873 +vt 0.375780 0.897365 +vt 0.344320 0.876514 +vt 0.351380 0.878048 +vt 0.344320 0.876514 +vt 0.348695 0.863959 +vt 0.351380 0.878048 +vt 0.344320 0.876514 +vt 0.354023 0.856166 +vt 0.351380 0.878048 +vt 0.348695 0.863959 +vt 0.351380 0.878048 +vt 0.360639 0.926249 +vt 0.359976 0.869622 +vt 0.360639 0.926249 +vt 0.351380 0.878048 +vt 0.354023 0.856166 +vt 0.359976 0.869622 +vt 0.351380 0.878048 +vt 0.359809 0.852883 +vt 0.359976 0.869622 +vt 0.354023 0.856166 +vt 0.365695 0.855248 +vt 0.359976 0.869622 +vt 0.368910 0.876776 +vt 0.359976 0.869622 +vt 0.365695 0.855248 +vt 0.371296 0.862137 +vt 0.368910 0.876776 +vt 0.365695 0.855248 +vt 0.376138 0.873873 +vt 0.368910 0.876776 +vt 0.371296 0.862137 +vt 0.342124 0.963339 +vt 0.339662 0.946763 +vt 0.342124 0.963339 +vt 0.339662 0.946763 +vt 0.338526 0.928680 +vt 0.339662 0.946763 +vt 0.338526 0.928680 +vt 0.359976 0.869622 +vt 0.368910 0.876776 +vt 0.360639 0.926249 +vt 0.827807 0.286028 +vt 0.823919 0.157147 +vt 0.862756 0.183227 +vt 0.788476 0.283421 +vt 0.789138 0.390362 +vt 0.755334 0.397635 +vt 0.788120 0.497298 +vt 0.751641 0.503802 +vt 0.760338 0.678072 +vt 0.829499 0.393381 +vt 0.831191 0.500740 +vt 0.876563 0.507363 +vt 0.831083 0.708298 +vt 0.874898 0.710721 +vt 0.876579 0.819640 +vt 0.900982 0.704927 +vt 0.873908 0.405011 +vt 0.897501 0.314156 +vt 0.901569 0.414794 +vt 0.871252 0.302666 +vt 0.894788 0.247060 +vt 0.905637 0.515438 +vt 0.788329 0.690006 +vt 0.789314 0.800362 +vt 0.762613 0.282678 +vt 0.772466 0.216986 +vt 0.785293 0.166593 +vt 0.835200 0.842853 +vt 0.827807 0.286028 +vt 0.862756 0.183227 +vt 0.823919 0.157147 +vt 0.788476 0.283421 +vt 0.789138 0.390362 +vt 0.755334 0.397635 +vt 0.788120 0.497298 +vt 0.751641 0.503802 +vt 0.760338 0.678072 +vt 0.829499 0.393381 +vt 0.831191 0.500740 +vt 0.876563 0.507363 +vt 0.831083 0.708298 +vt 0.874898 0.710721 +vt 0.876579 0.819640 +vt 0.900982 0.704927 +vt 0.873908 0.405011 +vt 0.901569 0.414794 +vt 0.897501 0.314156 +vt 0.871252 0.302666 +vt 0.894788 0.247060 +vt 0.905637 0.515438 +vt 0.788329 0.690006 +vt 0.789314 0.800362 +vt 0.762613 0.282678 +vt 0.772466 0.216986 +vt 0.785293 0.166593 +vt 0.835200 0.842853 +vn -0.982749 -0.171056 -0.070321 +vn -0.999526 -0.026369 0.015908 +vn -0.994374 0.063245 0.084975 +vn -0.803762 -0.256928 -0.536614 +vn -0.533529 -0.428361 -0.729283 +vn -0.785662 -0.093554 -0.611541 +vn 0.670793 -0.428609 -0.605253 +vn 0.793827 -0.482879 -0.369685 +vn 0.940069 -0.187917 0.284532 +vn 0.855610 -0.384557 0.346478 +vn -0.659042 -0.134526 0.739977 +vn 0.721944 -0.665072 0.190986 +vn -0.767470 -0.535473 0.352504 +vn -0.033758 -0.967654 -0.250012 +vn -0.892630 -0.410773 -0.185678 +vn -0.842026 -0.155902 -0.516417 +vn -0.985871 0.156537 0.059623 +vn -0.995141 0.096229 0.020838 +vn -0.516686 0.344284 0.783903 +vn -0.890603 0.065525 0.450037 +vn 0.979337 -0.183611 -0.084771 +vn 0.266049 -0.884584 -0.383052 +vn 0.615010 -0.763782 0.195958 +vn -0.671385 -0.602650 0.431341 +vn -0.566938 -0.119393 0.815063 +vn -0.940465 0.005938 0.339840 +vn -0.599129 0.392244 0.697989 +vn -0.671907 0.304445 0.675170 +vn 0.964186 0.238077 0.116898 +vn 0.750933 0.505529 0.424901 +vn 0.999526 -0.026370 0.015908 +vn 0.982748 -0.171057 -0.070322 +vn 0.994374 0.063248 0.084975 +vn 0.803761 -0.256930 -0.536614 +vn 0.998345 -0.021195 -0.053469 +vn 0.995141 0.096229 0.020836 +vn 0.985675 0.018259 0.167664 +vn 0.890604 0.065526 0.450034 +vn 0.940464 0.005940 0.339842 +vn 0.736582 -0.676293 0.008655 +vn 0.671388 -0.602657 0.431326 +vn -0.266048 -0.884584 -0.383053 +vn -0.615018 -0.763780 0.195942 +vn -0.979338 -0.183606 -0.084771 +vn -0.939869 -0.176226 0.292557 +vn -0.964186 0.238077 0.116899 +vn 0.566936 -0.119399 0.815063 +vn 0.599130 0.392237 0.697992 +vn 0.671907 0.304445 0.675169 +vn 0.927189 0.116145 0.356133 +vn 0.719359 0.095808 0.688000 +vn 0.960011 0.060957 0.273245 +vn 0.973140 0.025224 0.228828 +vn 0.533529 -0.428364 -0.729281 +vn 0.785662 -0.093553 -0.611541 +vn 0.842027 -0.155902 -0.516416 +vn 0.985871 0.156537 0.059619 +vn 0.892629 -0.410775 -0.185680 +vn 0.767464 -0.535473 0.352517 +vn -0.482561 -0.859416 -0.168933 +vn -0.245310 -0.922104 0.299245 +vn -0.830711 -0.429922 0.353675 +vn 0.659044 -0.134515 0.739978 +vn -0.940070 -0.187916 0.284528 +vn 0.516682 0.344289 0.783903 +vn 0.041213 -0.987681 -0.150958 +vn -0.000001 -0.946260 -0.323407 +vn -0.041212 -0.987681 -0.150957 +vn 0.501147 -0.716599 -0.485116 +vn -0.178110 -0.954125 -0.240671 +vn -0.269304 -0.369849 -0.889206 +vn -0.782868 -0.612231 -0.110863 +vn -0.900061 0.096460 -0.424955 +vn -0.478708 -0.433444 -0.763521 +vn -0.519010 -0.164788 -0.838734 +vn -0.470921 -0.164448 -0.866713 +vn -0.637991 -0.220334 -0.737848 +vn -0.830828 -0.161488 -0.532584 +vn -0.887711 -0.053173 -0.457321 +vn -0.949401 -0.207778 -0.235515 +vn -0.963247 -0.022103 -0.267705 +vn -0.311766 -0.947908 -0.065359 +vn -0.412009 -0.899489 -0.145492 +vn 0.198344 -0.673504 -0.712076 +vn 0.174971 0.064737 -0.982443 +vn -0.720875 -0.177023 -0.670077 +vn -0.447467 0.651616 -0.612511 +vn -0.991679 0.113596 0.060568 +vn -0.884241 -0.134293 -0.447307 +vn -0.954339 -0.228653 0.192236 +vn -0.920496 -0.357096 -0.158652 +vn -0.879633 -0.474662 -0.030691 +vn -0.000000 0.408295 -0.912850 +vn -0.360173 0.287176 -0.887584 +vn -0.359901 0.495774 -0.790367 +vn 0.000000 0.245609 -0.969369 +vn 0.360174 0.287176 -0.887584 +vn 0.339886 -0.019049 -0.940274 +vn 0.601406 0.330797 -0.727245 +vn 0.669191 -0.038826 -0.742076 +vn 0.886459 0.157233 -0.435279 +vn 0.887711 -0.053174 -0.457321 +vn 0.986989 0.030861 -0.157802 +vn 0.985621 -0.095168 -0.139619 +vn 0.478711 -0.433446 -0.763519 +vn 0.412008 -0.899490 -0.145491 +vn 0.782869 -0.612229 -0.110864 +vn -0.198343 -0.673502 -0.712078 +vn -0.174969 0.064737 -0.982443 +vn 0.720874 -0.177023 -0.670077 +vn 0.447468 0.651615 -0.612511 +vn 0.991679 0.113595 0.060568 +vn 0.884240 -0.134293 -0.447308 +vn 0.954339 -0.228653 0.192237 +vn 0.920495 -0.357097 -0.158651 +vn 0.879632 -0.474663 -0.030691 +vn 0.178111 -0.954125 -0.240670 +vn 0.311767 -0.947908 -0.065357 +vn -0.501145 -0.716599 -0.485118 +vn 0.000000 -0.483633 -0.875271 +vn 0.585071 0.016034 -0.810824 +vn -0.196860 0.622954 -0.757083 +vn -0.585071 0.016033 -0.810824 +vn -0.030436 -0.139716 -0.989724 +vn 0.269308 -0.369850 -0.889204 +vn 0.467459 -0.798313 -0.379709 +vn 0.230986 -0.966671 0.110420 +vn 0.900060 0.096466 -0.424955 +vn 0.519007 -0.164788 -0.838735 +vn 0.470922 -0.164449 -0.866712 +vn 0.637992 -0.220334 -0.737848 +vn 0.830828 -0.161488 -0.532585 +vn 0.949400 -0.207778 -0.235516 +vn -0.986224 0.164337 -0.018861 +vn -0.986989 0.030862 -0.157801 +vn -0.968164 0.062104 0.242491 +vn -0.973140 0.025224 0.228827 +vn -0.888401 -0.122393 0.442451 +vn -0.778982 -0.118055 0.615832 +vn -0.239758 -0.297161 0.924236 +vn -0.198559 0.129387 0.971511 +vn 0.968164 0.062104 0.242490 +vn 0.888401 -0.122393 0.442451 +vn 0.860649 0.034484 0.508030 +vn 0.805486 -0.223678 0.548780 +vn 0.578165 0.003858 0.815911 +vn 0.364797 -0.616185 0.698025 +vn 0.161378 -0.422475 0.891892 +vn -0.998345 -0.021193 -0.053469 +vn -0.985675 0.018260 0.167664 +vn 0.239771 -0.297152 0.924235 +vn 0.380867 -0.657281 0.650325 +vn 0.778983 -0.118054 0.615832 +vn 0.198553 0.129397 0.971511 +vn -0.750936 0.505530 0.424895 +vn -0.860648 0.034484 0.508032 +vn -0.805486 -0.223677 0.548782 +vn -0.364796 -0.616184 0.698026 +vn -0.578165 0.003857 0.815911 +vn -0.161389 -0.422470 0.891893 +vn -0.475538 0.238218 0.846827 +vn -0.669191 -0.038826 -0.742075 +vn -0.343712 -0.221056 -0.912687 +vn -0.339886 -0.019049 -0.940274 +vn -0.000000 -0.193908 -0.981020 +vn 0.000000 -0.013050 -0.999915 +vn 0.705304 -0.566188 0.426589 +vn 0.744177 -0.586468 0.319776 +vn 0.259480 -0.960362 -0.101856 +vn -0.960011 0.060956 0.273245 +vn -0.927188 0.116146 0.356135 +vn 0.343712 -0.221055 -0.912687 +vn 0.986224 0.164339 -0.018862 +vn 0.723259 0.487732 -0.488891 +vn 0.417608 0.678605 -0.604235 +vn -0.985621 -0.095167 -0.139619 +vn -0.886459 0.157233 -0.435280 +vn -0.723260 0.487730 -0.488890 +vn -0.736583 -0.676292 0.008651 +vn -0.705305 -0.566188 0.426587 +vn -0.744177 -0.586467 0.319776 +vn -0.230985 -0.966671 0.110419 +vn -0.259480 -0.960362 -0.101854 +vn -0.798072 -0.492809 -0.346728 +vn -0.670793 -0.428610 -0.605253 +vn -0.601407 0.330795 -0.727244 +vn -0.417609 0.678605 -0.604234 +vn 0.939867 -0.176233 0.292560 +vn -0.719359 0.095809 0.688000 +vn 0.196853 0.622953 -0.757085 +vn 0.030436 -0.139717 -0.989724 +vn 0.963247 -0.022101 -0.267705 +vn -0.380869 -0.657292 0.650312 +vn 0.359901 0.495774 -0.790366 +vn 0.475535 0.238222 0.846827 +vn -0.467460 -0.798312 -0.379709 +vn -0.084883 0.830185 -0.550988 +vn 0.009986 0.253650 -0.967245 +vn -0.161582 0.276281 -0.947397 +vn -0.088416 0.831239 -0.548839 +vn -0.143851 0.985951 -0.084891 +vn -0.066261 0.996005 -0.059868 +vn -0.132895 0.896891 0.421812 +vn -0.075321 0.876242 0.475949 +vn -0.155404 0.376961 0.913099 +vn -0.132014 0.339424 0.931324 +vn -0.072447 0.995720 -0.057380 +vn -0.109956 0.820781 -0.560561 +vn -0.105290 0.900329 0.422281 +vn -0.053216 0.391273 0.918735 +vn 0.100088 -0.806585 0.582583 +vn 0.245491 -0.233347 0.940895 +vn 0.638014 -0.059602 0.767715 +vn 0.029613 -0.245355 0.968981 +vn 0.037988 -0.832320 0.552992 +vn 0.017738 -0.260976 0.965182 +vn -0.007914 -0.793312 0.608764 +vn 0.032519 -0.218178 0.975367 +vn 0.044700 -0.996105 0.076011 +vn -0.002182 -0.995603 0.093647 +vn 0.030253 -0.902431 -0.429770 +vn 0.061575 -0.942931 -0.327245 +vn 0.109956 0.820781 -0.560561 +vn 0.091091 0.793258 -0.602034 +vn 0.148207 0.147759 -0.977856 +vn 0.014386 0.996091 -0.087157 +vn 0.072447 0.995720 -0.057380 +vn 0.017836 0.900549 0.434389 +vn 0.105288 0.900330 0.422280 +vn 0.040528 0.385122 0.921975 +vn 0.053215 0.391272 0.918735 +vn 0.054727 -0.463812 -0.884242 +vn 0.088299 -0.451207 -0.888040 +vn 0.145963 -0.430479 -0.890720 +vn 0.097189 0.206868 -0.973530 +vn 0.155404 0.376961 0.913099 +vn 0.161582 0.276280 -0.947397 +vn 0.049568 0.175061 -0.983309 +vn 0.007913 -0.793311 0.608765 +vn -0.062220 -0.991801 0.111624 +vn 0.002182 -0.995603 0.093648 +vn -0.072133 -0.749937 0.657564 +vn -0.032520 -0.218178 0.975367 +vn -0.060924 -0.151716 0.986545 +vn -0.009008 0.397043 0.917756 +vn -0.019628 0.460802 0.887286 +vn 0.042549 0.892139 0.449753 +vn 0.072480 0.907322 0.414143 +vn 0.065470 0.992463 -0.103593 +vn 0.119124 0.987465 -0.103550 +vn 0.014335 0.787944 -0.615580 +vn 0.052862 0.801248 -0.595993 +vn -0.049569 0.175060 -0.983309 +vn -0.048350 0.276067 -0.959922 +vn -0.054726 -0.463812 -0.884242 +vn -0.115337 -0.367578 -0.922813 +vn -0.030253 -0.902431 -0.429770 +vn -0.060985 -0.876417 -0.477677 +vn -0.028789 -0.992688 0.117221 +vn -0.063811 -0.715625 0.695564 +vn -0.092714 -0.172310 0.980670 +vn -0.123731 0.472957 0.872354 +vn -0.044144 0.896765 0.440300 +vn -0.008209 0.993414 -0.114287 +vn -0.034904 0.766141 -0.641724 +vn -0.062581 0.784151 -0.617406 +vn -0.038921 0.243228 -0.969188 +vn -0.043781 0.783368 -0.620015 +vn -0.039682 0.272329 -0.961386 +vn 0.026909 0.778852 -0.626631 +vn 0.020179 0.226683 -0.973760 +vn 0.014891 0.992029 -0.125128 +vn -0.054604 0.993106 -0.103724 +vn -0.010281 0.894536 0.446877 +vn -0.075010 0.884106 0.461227 +vn -0.043660 0.443860 0.895032 +vn -0.084287 0.429637 0.899059 +vn -0.045362 -0.192641 0.980220 +vn -0.088891 -0.162311 0.982728 +vn -0.038156 -0.778896 0.625992 +vn -0.097981 -0.712467 0.694831 +vn -0.032783 -0.993722 0.106965 +vn -0.066047 -0.988634 0.135058 +vn -0.088950 0.990999 -0.100041 +vn -0.094142 0.896804 0.432297 +vn -0.073309 0.436879 0.896528 +vn -0.007060 -0.157038 0.987567 +vn -0.052173 -0.733399 0.677794 +vn -0.003296 -0.993291 0.115596 +vn -0.040527 0.385122 0.921976 +vn -0.017737 -0.260977 0.965182 +vn -0.017836 0.900548 0.434392 +vn -0.014386 0.996091 -0.087157 +vn -0.091091 0.793257 -0.602035 +vn -0.097190 0.206867 -0.973530 +vn -0.006090 -0.892507 -0.450993 +vn -0.035739 -0.876438 -0.480186 +vn 0.017763 -0.334314 -0.942294 +vn -0.048012 -0.360941 -0.931352 +vn -0.011044 -0.886308 -0.462965 +vn 0.003309 -0.373688 -0.927549 +vn 0.035568 -0.383621 -0.922805 +vn -0.009511 0.273399 -0.961854 +vn 0.046864 -0.871216 -0.488658 +vn -0.000000 0.073414 -0.997302 +vn 0.000000 0.054308 -0.998524 +vn 0.525620 0.017177 -0.850546 +vn -0.525620 0.017177 -0.850546 +vn -0.490269 0.083576 -0.867555 +vn -0.876821 -0.024879 -0.480174 +vn -0.855450 0.100382 -0.508064 +vn -0.984455 -0.062283 -0.164226 +vn -0.983600 0.050351 -0.173191 +vn -0.951589 -0.118462 0.283630 +vn -0.955566 0.026426 0.293592 +vn -0.589239 -0.205447 0.781402 +vn -0.520037 0.006818 0.854117 +vn 0.000000 -0.290965 0.956734 +vn -0.000000 -0.018132 0.999836 +vn 0.520037 0.006818 0.854117 +vn -0.240179 0.868861 0.432891 +vn 0.179855 0.913230 0.365600 +vn 0.490269 0.083576 -0.867555 +vn 0.876820 -0.024879 -0.480174 +vn 0.000000 0.988483 -0.151330 +vn -0.021404 0.999458 -0.025018 +vn 0.018615 0.982608 -0.184758 +vn -0.379691 0.923230 -0.059004 +vn -0.179855 0.913230 0.365600 +vn 0.240179 0.868860 0.432892 +vn -0.000000 0.911287 0.411771 +vn 0.346758 0.192167 -0.918058 +vn 0.263969 0.836714 -0.479823 +vn 0.395396 0.905664 -0.153082 +vn -0.000000 0.832127 -0.554586 +vn -0.000000 0.154786 -0.987948 +vn -0.346758 0.192167 -0.918058 +vn -0.161090 0.556455 -0.815112 +vn -0.319126 0.616539 -0.719749 +vn 0.122193 0.984214 0.128027 +vn -0.244038 0.641141 0.727587 +vn -0.000000 0.626771 0.779204 +vn -0.495960 0.678947 0.541345 +vn -0.494282 0.849041 0.186586 +vn -0.966084 0.253069 -0.051365 +vn -0.992033 0.060494 -0.110505 +vn 0.575377 0.439376 -0.689848 +vn 0.972343 0.149244 -0.179652 +vn 0.319126 0.616540 -0.719748 +vn 0.161090 0.556456 -0.815112 +vn -0.018614 0.982607 -0.184761 +vn 0.739893 0.671688 0.037326 +vn 0.021405 0.999458 -0.025022 +vn 0.494282 0.849041 0.186586 +vn -0.122194 0.984214 0.128025 +vn 0.000000 0.998199 0.059994 +vn -0.739893 0.671688 0.037326 +vn -0.263969 0.836714 -0.479822 +vn -0.395396 0.905664 -0.153081 +vn 0.589239 -0.205448 0.781402 +vn 0.955566 0.026426 0.293592 +vn 0.379692 0.923230 -0.059004 +vn 0.951589 -0.118462 0.283630 +vn 0.983600 0.050351 -0.173191 +vn 0.984455 -0.062283 -0.164226 +vn 0.855450 0.100382 -0.508064 +vn 0.992033 0.060494 -0.110505 +vn 0.966084 0.253069 -0.051365 +vn 0.495960 0.678947 0.541345 +vn 0.244038 0.641142 0.727587 +vn -0.972343 0.149244 -0.179652 +vn -0.575377 0.439377 -0.689847 +vn -0.000000 0.583238 -0.812302 +vn 0.084883 0.830185 -0.550988 +vn -0.009986 0.253649 -0.967245 +vn 0.088416 0.831239 -0.548839 +vn 0.132895 0.896891 0.421812 +vn 0.066261 0.996005 -0.059867 +vn 0.075321 0.876242 0.475949 +vn 0.143852 0.985952 -0.084891 +vn 0.177624 0.381362 0.907201 +vn 0.496821 0.561897 0.661394 +vn 0.132014 0.339424 0.931324 +vn 0.001336 0.898197 0.439591 +vn 0.349509 0.317287 -0.881574 +vn 0.105926 0.883378 -0.456534 +vn -0.018221 0.999216 -0.035152 +vn -0.358475 0.816884 0.451881 +vn -0.475757 0.571224 0.668848 +vn -0.615136 0.488532 0.618824 +vn -0.149318 0.901566 0.406057 +vn -0.283795 0.953568 0.100841 +vn -0.087838 0.995762 -0.027264 +vn -0.269371 0.934402 -0.233093 +vn -0.142165 0.898632 -0.415030 +vn -0.197559 0.735650 -0.647912 +vn -0.255530 0.454016 -0.853565 +vn -0.300421 0.330077 -0.894872 +vn 0.228265 0.788936 0.570504 +vn 0.185299 0.630124 0.754061 +vn 0.000000 0.544440 0.838800 +vn -0.185298 0.630125 0.754060 +vn -0.060447 0.780370 0.622389 +vn -0.159805 0.769325 0.618548 +vn -0.098551 0.794661 0.599000 +vn 0.159805 0.769326 0.618547 +vn 0.060448 0.780369 0.622390 +vn 0.000000 0.757529 0.652801 +vn -0.106589 0.690257 0.715670 +vn -0.280673 0.535358 0.796627 +vn 0.197559 0.735650 -0.647912 +vn 0.255530 0.454016 -0.853565 +vn 0.300421 0.330077 -0.894872 +vn 0.142165 0.898632 -0.415030 +vn 0.269371 0.934402 -0.233093 +vn 0.087838 0.995762 -0.027264 +vn 0.283795 0.953568 0.100841 +vn 0.149318 0.901566 0.406058 +vn 0.358475 0.816883 0.451882 +vn 0.098551 0.794662 0.598999 +vn 0.106588 0.690257 0.715671 +vn -0.000000 0.693252 0.720696 +vn 0.128750 0.565714 -0.814488 +vn 0.000000 0.535507 -0.844531 +vn -0.128750 0.565714 -0.814488 +vn -0.120002 0.633377 0.764482 +vn -0.000000 0.638031 0.770010 +vn 0.120002 0.633377 0.764482 +vn 0.280673 0.535358 0.796627 +vn -0.228265 0.788936 0.570504 +vn 0.615136 0.488532 0.618825 +vn 0.039682 0.272328 -0.961386 +vn -0.026909 0.778854 -0.626628 +vn -0.020180 0.226682 -0.973760 +vn 0.043781 0.783368 -0.620014 +vn 0.038920 0.243228 -0.969188 +vn 0.062579 0.784151 -0.617406 +vn 0.034904 0.766141 -0.641724 +vn 0.008209 0.993414 -0.114287 +vn -0.119123 0.987465 -0.103548 +vn 0.044144 0.896765 0.440300 +vn -0.072479 0.907321 0.414144 +vn 0.123734 0.472957 0.872354 +vn 0.019625 0.460801 0.887286 +vn 0.092719 -0.172311 0.980669 +vn 0.060924 -0.151716 0.986545 +vn 0.063811 -0.715625 0.695564 +vn 0.072130 -0.749939 0.657563 +vn 0.028792 -0.992689 0.117221 +vn 0.062217 -0.991801 0.111626 +vn 0.066047 -0.988634 0.135060 +vn 0.006091 -0.892507 -0.450992 +vn 0.032783 -0.993722 0.106968 +vn 0.035738 -0.876438 -0.480188 +vn 0.003295 -0.993291 0.115595 +vn 0.011042 -0.886308 -0.462965 +vn -0.046861 -0.871216 -0.488658 +vn -0.003310 -0.373687 -0.927549 +vn -0.035568 -0.383621 -0.922806 +vn 0.009511 0.273399 -0.961854 +vn 0.048354 0.276067 -0.959921 +vn -0.052859 0.801247 -0.595994 +vn -0.014336 0.787945 -0.615579 +vn 0.075010 0.884106 0.461227 +vn 0.043660 0.443860 0.895032 +vn 0.010281 0.894537 0.446876 +vn 0.084287 0.429637 0.899060 +vn 0.094141 0.896804 0.432297 +vn 0.073310 0.436878 0.896528 +vn 0.007062 -0.157034 0.987568 +vn 0.052175 -0.733397 0.677795 +vn -0.014891 0.992029 -0.125128 +vn 0.054604 0.993106 -0.103726 +vn 0.088949 0.990999 -0.100041 +vn 0.097982 -0.712469 0.694830 +vn 0.038156 -0.778895 0.625992 +vn -0.065470 0.992463 -0.103591 +vn 0.060983 -0.876418 -0.477674 +vn -0.017764 -0.334311 -0.942295 +vn 0.048012 -0.360941 -0.931352 +vn 0.045363 -0.192639 0.980221 +vn 0.088890 -0.162311 0.982728 +vn 0.009008 0.397046 0.917755 +vn -0.042548 0.892139 0.449753 +vn 0.115339 -0.367578 -0.922813 +vn 0.000000 0.423260 -0.906008 +vn 0.186194 0.653374 0.733781 +vn 0.122696 0.589994 0.798030 +vn 0.000000 0.571431 0.820650 +vn -0.122696 0.589994 0.798030 +vn 0.000000 0.523654 0.851931 +vn -0.096928 0.515450 0.851420 +vn 0.949792 0.171251 0.261855 +vn 0.818555 0.329138 0.470783 +vn 0.817279 0.281924 0.502567 +vn -0.165207 0.528722 0.832562 +vn -0.186194 0.653374 0.733781 +vn 0.096928 0.515450 0.851420 +vn 0.165207 0.528721 0.832563 +vn -0.931515 -0.339453 0.130579 +vn -0.996587 -0.016589 -0.080870 +vn -0.914650 -0.365776 -0.172113 +vn -0.988517 -0.081797 0.127055 +vn -0.912002 0.063087 0.405304 +vn -0.946626 0.135090 0.292660 +vn -0.817279 0.281924 0.502567 +vn -0.818555 0.329138 0.470783 +vn -0.953216 0.131857 -0.272016 +vn -0.928928 0.369654 -0.021177 +vn -0.875857 -0.115079 -0.468649 +vn -0.619283 -0.088642 -0.780148 +vn -0.594353 -0.128670 -0.793844 +vn -0.931881 0.359737 -0.046759 +vn -0.957531 0.286279 0.034348 +vn -0.768954 -0.289991 -0.569750 +vn -0.953567 0.152043 0.259987 +vn -0.711671 0.696806 -0.089363 +vn -0.589840 -0.172895 -0.788794 +vn -0.967617 -0.190772 -0.165297 +vn -0.994872 -0.100202 0.013755 +vn -0.100088 -0.806585 0.582583 +vn -0.669469 -0.120119 0.733064 +vn -0.245491 -0.233347 0.940895 +vn -0.975587 -0.047215 0.214480 +vn -0.145963 -0.430479 -0.890720 +vn -0.061575 -0.942931 -0.327245 +vn -0.044699 -0.996105 0.076010 +vn -0.148207 0.147760 -0.977856 +vn -0.088300 -0.451209 -0.888039 +vn -0.029611 -0.245355 0.968981 +vn -0.037987 -0.832321 0.552990 +vn 0.994872 -0.100202 0.013755 +vn 0.975587 -0.047214 0.214480 +vn 0.931881 0.359737 -0.046759 +vn 0.957531 0.286279 0.034348 +vn 0.928928 0.369654 -0.021177 +vn 0.967617 -0.190772 -0.165297 +vn 0.953216 0.131857 -0.272016 +vn 0.996587 -0.016589 -0.080870 +vn 0.941260 -0.333881 0.050538 +vn 0.914650 -0.365776 -0.172113 +vn 0.996990 0.041095 0.065748 +vn 0.875857 -0.115079 -0.468648 +vn 0.768954 -0.289991 -0.569749 +vn 0.946626 0.135090 0.292660 +vn 0.902221 0.111126 0.416712 +vn 0.952947 -0.182390 0.242129 +vn 0.619283 -0.088642 -0.780148 +vn 0.594353 -0.128671 -0.793844 +vn -0.450929 0.110667 -0.885673 +vn -0.460105 0.120014 -0.879716 +vn 0.450928 0.110667 -0.885673 +vn 0.460105 0.120014 -0.879716 +vn -0.349509 0.317286 -0.881574 +vn -0.105926 0.883378 -0.456534 +vn 0.018221 0.999216 -0.035152 +vn -0.001336 0.898197 0.439591 +vn -0.216238 0.414820 0.883836 +vn 0.589840 -0.172894 -0.788794 +vn -0.962465 -0.266643 0.050624 +vn -0.755178 0.622050 0.206788 +vn -0.721885 0.499700 -0.478730 +vn -0.368883 -0.274203 0.888110 +vn -0.477434 -0.864233 0.158612 +vn -0.051268 -0.279636 0.958736 +vn -0.066090 -0.985902 0.153720 +vn -0.036251 -0.212591 0.976469 +vn -0.072507 -0.984975 0.156742 +vn -0.585601 -0.806963 0.076692 +vn -0.537037 -0.832077 0.138707 +vn -0.937609 -0.347555 0.009786 +vn -0.736072 0.593025 0.326374 +vn -0.760756 0.533074 -0.370247 +vn -0.353151 -0.393848 0.848627 +vn -0.501624 -0.863675 0.049392 +vn -0.025312 -0.410912 0.911324 +vn -0.100373 -0.994700 0.022310 +vn -0.034102 -0.368510 0.928998 +vn -0.074633 -0.996580 -0.035484 +vn -0.519101 -0.854061 0.033374 +vn -0.460249 -0.885384 0.065314 +vn -0.046020 0.457339 0.888101 +vn -0.028470 0.975615 -0.217634 +vn -0.365442 0.397225 0.841822 +vn 0.000859 0.969584 -0.244759 +vn 0.031226 0.372639 0.927451 +vn -0.135415 0.954586 -0.265382 +vn -0.049303 0.390374 0.919335 +vn -0.262467 0.920527 -0.289380 +vn -0.312053 0.911286 -0.268667 +vn -0.289191 0.907371 -0.305035 +vn 0.017780 0.444106 0.895798 +vn -0.013442 0.999872 -0.008669 +vn -0.322553 0.431858 0.842293 +vn 0.029603 0.999546 0.005561 +vn 0.071090 0.325376 0.942909 +vn -0.129129 0.991586 0.009126 +vn -0.057279 0.321975 0.945014 +vn -0.220063 0.962148 0.160760 +vn -0.332763 0.932080 0.143165 +vn -0.282102 0.955166 0.089875 +vn 0.004878 0.317921 -0.948105 +vn -0.349773 0.316486 -0.881757 +vn 0.041307 0.301210 -0.952663 +vn -0.073031 0.235927 -0.969023 +vn -0.335055 0.758837 -0.558484 +vn -0.077827 0.160113 -0.984026 +vn 0.057058 0.212251 -0.975548 +vn -0.379001 -0.549328 -0.744713 +vn -0.023047 -0.566417 -0.823797 +vn -0.307785 0.201660 -0.929840 +vn 0.019331 0.227067 -0.973687 +vn -0.023450 -0.535412 -0.844265 +vn -0.371024 -0.505572 -0.778934 +vn -0.038184 -0.490290 -0.870722 +vn -0.022783 -0.468222 -0.883317 +vn -0.456675 -0.878326 0.141392 +vn -0.049253 -0.991709 -0.118690 +vn -0.484818 -0.870550 0.084228 +vn -0.024293 -0.504476 0.863084 +vn -0.138331 -0.330884 0.933478 +vn -0.122736 0.362116 0.924017 +vn -0.031677 0.311431 0.949741 +vn -0.183687 0.935127 0.302978 +vn -0.245504 0.927403 0.282227 +vn -0.088085 0.371504 -0.924244 +vn -0.002224 -0.333359 -0.942797 +vn -0.121187 0.976373 0.178911 +vn -0.137041 0.851982 -0.505318 +vn -0.140478 0.706015 0.694125 +vn -0.803876 0.142665 0.577434 +vn -0.197898 0.846457 0.494315 +vn -0.043433 0.920343 0.388694 +vn -0.081957 0.080713 0.993362 +vn -0.633351 0.042649 0.772689 +vn -0.491976 -0.683057 0.539808 +vn -0.977995 0.011296 -0.208323 +vn -0.614682 -0.705048 -0.353656 +vn -0.579114 -0.082379 -0.811074 +vn -0.030976 -0.895807 -0.443363 +vn -0.039600 -0.075987 -0.996322 +vn -0.208152 -0.882780 -0.421157 +vn -0.308201 0.048408 -0.950089 +vn -0.712357 -0.547478 -0.439107 +vn 0.517961 -0.612453 0.597176 +vn -0.073564 -0.969292 0.234652 +vn 0.199784 -0.972457 0.120055 +vn 0.181384 -0.549229 0.815750 +vn 0.552221 0.000965 0.833697 +vn 0.231361 0.077626 0.969766 +vn 0.336810 0.443527 0.830568 +vn 0.161508 0.616307 0.770766 +vn -0.049476 0.768220 -0.638271 +vn -0.464532 0.834069 0.297557 +vn -0.149643 -0.745680 0.649283 +vn -0.073204 -0.814162 0.576004 +vn -0.044089 0.392668 0.918623 +vn -0.439375 -0.800395 -0.407820 +vn -0.213934 -0.912750 -0.348024 +vn -0.582624 0.611843 -0.534975 +vn -0.066699 0.071462 0.995211 +vn 0.081609 0.701984 0.707502 +vn 0.272043 0.584628 0.764332 +vn 0.133582 0.402371 0.905678 +vn 0.161669 0.581152 0.797575 +vn -0.225449 0.599203 0.768198 +vn 0.402476 0.592780 0.697585 +vn 0.519520 0.414562 0.747153 +vn 0.653753 0.743209 0.142295 +vn 0.773116 0.625663 0.104103 +vn 0.355710 0.820967 -0.446635 +vn 0.466646 0.677404 -0.568652 +vn 0.104449 0.823004 -0.558351 +vn 0.061203 0.690791 -0.720460 +vn -0.127414 0.886168 -0.445502 +vn -0.295559 0.804021 -0.515941 +vn -0.332672 0.930706 0.152040 +vn -0.468071 0.868347 0.163959 +vn -0.068206 0.698705 0.712151 +vn 0.000351 0.844917 0.534898 +vn 0.045366 0.937181 0.345882 +vn -0.337668 0.904151 0.261709 +vn 0.299982 0.909997 0.286211 +vn 0.410322 0.797279 0.442699 +vn 0.628317 0.744565 -0.225480 +vn 0.752291 0.632879 -0.183093 +vn 0.417258 0.459663 -0.783967 +vn 0.541971 0.284432 -0.790801 +vn 0.186266 0.380866 -0.905674 +vn 0.167307 0.182098 -0.968942 +vn -0.057305 0.476026 -0.877562 +vn -0.210535 0.356348 -0.910325 +vn -0.347542 0.825614 -0.444495 +vn -0.482918 0.767154 -0.422214 +vn -0.170595 0.968871 0.179404 +vn 0.013227 0.646625 0.762693 +vn 0.043796 0.791773 0.609243 +vn -0.341128 0.769474 0.539946 +vn 0.294190 0.794544 0.531179 +vn 0.415904 0.645429 0.640659 +vn 0.594825 0.803522 -0.023138 +vn 0.724233 0.689263 -0.020062 +vn 0.355421 0.688652 -0.632008 +vn 0.484459 0.527120 -0.698172 +vn 0.118367 0.639464 -0.759655 +vn 0.099737 0.466464 -0.878899 +vn -0.126025 0.712241 -0.690529 +vn -0.279305 0.601360 -0.748568 +vn -0.396359 0.905046 -0.154246 +vn -0.528231 0.837331 -0.140889 +vn -0.182478 0.862247 0.472475 +vn -0.215354 -0.553136 -0.804776 +vn -0.266773 -0.846721 -0.460322 +vn -0.525163 -0.838744 -0.143915 +vn -0.068875 -0.442523 -0.894109 +vn -0.125939 0.057112 -0.990393 +vn 0.051445 -0.009167 -0.998634 +vn 0.036317 0.557235 -0.829560 +vn 0.272351 0.178303 -0.945533 +vn 0.265795 0.779911 -0.566650 +vn 0.088278 0.306778 -0.947679 +vn 0.022012 0.830247 -0.556960 +vn -0.430399 0.298026 -0.852020 +vn -0.318734 0.785526 -0.530431 +vn 0.180490 0.321157 -0.929667 +vn 0.183491 0.805888 -0.562917 +vn 0.984817 -0.052846 0.165355 +vn 0.983352 -0.144837 0.109731 +vn -0.478686 -0.877263 0.035629 +vn -0.033566 -0.826734 -0.561591 +vn 0.121359 -0.376269 -0.918528 +vn -0.230142 -0.687366 -0.688885 +vn -0.021104 -0.218550 -0.975597 +vn -0.494279 -0.560024 -0.664877 +vn -0.410400 -0.137336 -0.901505 +vn 0.226840 -0.615603 -0.754703 +vn 0.199962 -0.162028 -0.966314 +vn 0.984480 0.110513 0.136330 +vn 0.980951 0.034097 0.191239 +vn -0.466395 -0.879475 -0.094867 +vn -0.137309 -0.987330 -0.079541 +vn -0.281909 -0.908863 -0.307401 +vn -0.530168 -0.809193 -0.253237 +vn 0.193643 -0.934376 -0.299071 +vn 0.982641 0.170810 0.072389 +vn 0.618675 0.092248 0.780212 +vn 0.423191 -0.552459 0.718121 +vn 0.234027 -0.910409 0.341154 +vn -0.225384 -0.973962 -0.024512 +vn -0.034880 0.958356 -0.283440 +vn -0.050622 0.862173 -0.504078 +vn -0.244468 0.824123 -0.510937 +vn -0.265775 0.827138 -0.495183 +vn -0.142527 0.898146 -0.415956 +vn -0.115733 0.513051 0.850520 +vn 0.011072 0.529688 0.848121 +vn -0.052145 -0.985729 0.160063 +vn 0.002850 -0.630404 -0.776262 +vn -0.018019 -0.625047 -0.780379 +vn -0.007309 0.248428 -0.968623 +vn -0.293769 0.274570 -0.915593 +vn -0.033262 0.958797 -0.282140 +vn -0.720848 0.414036 -0.555835 +vn -0.782369 0.588072 0.205112 +vn 0.226407 -0.967842 0.109641 +vn -0.467329 -0.880242 0.082330 +vn 0.271901 -0.834486 0.479274 +vn -0.413376 -0.793184 0.447189 +vn 0.341024 -0.435077 0.833313 +vn -0.401128 -0.385376 0.831012 +vn 0.323959 0.079585 0.942718 +vn -0.391638 0.096071 0.915090 +vn 0.977167 0.210720 -0.027252 +vn 0.984525 0.142092 -0.102569 +vn 0.986320 0.063115 -0.152283 +vn 0.982921 -0.010609 -0.183723 +vn 0.984270 -0.100513 -0.145294 +vn 0.269965 0.540727 0.796701 +vn 0.982009 -0.172897 -0.075933 +vn 0.240990 0.884743 0.398941 +vn 0.977594 -0.209117 0.024069 +vn 0.195198 0.975500 -0.101478 +vn 0.048659 0.249704 0.967099 +vn -0.427697 0.546692 0.719863 +vn -0.425129 0.841556 0.333240 +vn -0.412061 0.906348 -0.093480 +vn -0.012876 0.581912 0.813150 +vn 0.056112 0.902654 0.426693 +vn 0.037327 0.995327 -0.089054 +vn -0.365933 -0.596387 -0.714433 +vn -0.942771 -0.328874 0.055005 +vn -0.504976 -0.851686 0.140107 +vn -0.374045 -0.276519 0.885227 +vn -0.003392 -0.233122 0.972441 +vn 0.011432 0.562422 0.826771 +vn 0.257933 0.887106 0.382771 +vn 0.236829 0.967064 -0.093272 +vn -0.044019 -0.978228 0.202812 +vn -0.051272 -0.149628 0.987412 +vn -0.069477 0.210790 -0.975059 +vn -0.055384 0.928895 -0.366178 +vn -0.008137 0.931388 0.363937 +vn -0.038017 0.997237 0.063819 +vn -0.004604 0.229452 -0.973309 +vn 0.176778 0.969431 0.170158 +vn 0.999983 -0.005766 -0.000375 +vn 0.104821 0.988955 -0.104793 +vn 0.153101 0.907826 -0.390400 +vn -0.354282 0.499223 0.790734 +vn -0.195201 0.975499 -0.101479 +vn -0.983352 -0.144836 0.109731 +vn -0.977594 -0.209117 0.024068 +vn -0.183489 0.805889 -0.562916 +vn 0.412064 0.906347 -0.093481 +vn 0.318736 0.785526 -0.530430 +vn -0.037325 0.995327 -0.089054 +vn -0.022009 0.830247 -0.556961 +vn -0.265795 0.779910 -0.566651 +vn -0.088272 0.306776 -0.947680 +vn -0.272351 0.178301 -0.945533 +vn 0.021107 -0.218551 -0.975597 +vn -0.121360 -0.376269 -0.918528 +vn 0.230144 -0.687366 -0.688884 +vn 0.033566 -0.826734 -0.561591 +vn 0.281909 -0.908863 -0.307401 +vn 0.137309 -0.987330 -0.079540 +vn 0.225383 -0.973962 -0.024511 +vn -0.323962 0.079584 0.942717 +vn -0.984270 -0.100513 -0.145293 +vn -0.982920 -0.010608 -0.183726 +vn -0.269968 0.540726 0.796701 +vn 0.391635 0.096071 0.915091 +vn 0.427696 0.546692 0.719864 +vn -0.048660 0.249703 0.967099 +vn 0.012878 0.581911 0.813151 +vn -0.272043 0.584628 0.764332 +vn -0.257933 0.887106 0.382771 +vn -0.982009 -0.172896 -0.075933 +vn -0.240994 0.884743 0.398939 +vn 0.425129 0.841557 0.333239 +vn -0.056109 0.902654 0.426693 +vn -0.236829 0.967064 -0.093272 +vn 0.477434 -0.864235 0.158605 +vn 0.962466 -0.266641 0.050624 +vn 0.368882 -0.274202 0.888110 +vn 0.379001 -0.549324 -0.744716 +vn 0.066089 -0.985902 0.153721 +vn 0.023048 -0.566418 -0.823796 +vn 0.072507 -0.984975 0.156740 +vn 0.023452 -0.535411 -0.844266 +vn 0.537039 -0.832076 0.138707 +vn -0.271900 -0.834485 0.479275 +vn -0.986320 0.063114 -0.152283 +vn -0.984525 0.142090 -0.102568 +vn -0.341026 -0.435076 0.833313 +vn 0.413376 -0.793184 0.447190 +vn 0.401126 -0.385378 0.831012 +vn -0.234028 -0.910409 0.341156 +vn -0.423190 -0.552461 0.718121 +vn -0.199961 -0.162029 -0.966314 +vn -0.984480 0.110512 0.136331 +vn -0.980951 0.034095 0.191239 +vn -0.226838 -0.615603 -0.754704 +vn 0.410404 -0.137335 -0.901503 +vn 0.494279 -0.560024 -0.664877 +vn -0.982641 0.170812 0.072389 +vn -0.193643 -0.934376 -0.299073 +vn 0.530167 -0.809193 -0.253237 +vn -0.977166 0.210722 -0.027252 +vn -0.226408 -0.967842 0.109640 +vn 0.467327 -0.880243 0.082330 +vn -0.984817 -0.052846 0.165355 +vn -0.180490 0.321155 -0.929668 +vn 0.430402 0.298027 -0.852018 +vn 0.046018 0.457339 0.888101 +vn 0.365443 0.397223 0.841823 +vn 0.051267 -0.279636 0.958737 +vn -0.031228 0.372640 0.927450 +vn 0.036249 -0.212592 0.976469 +vn 0.049302 0.390373 0.919336 +vn 0.312050 0.911285 -0.268671 +vn 0.585600 -0.806964 0.076693 +vn 0.077829 0.160110 -0.984026 +vn 0.335058 0.758836 -0.558483 +vn -0.057056 0.212249 -0.975549 +vn -0.019330 0.227065 -0.973688 +vn 0.028470 0.975615 -0.217636 +vn -0.000859 0.969584 -0.244757 +vn 0.135416 0.954585 -0.265386 +vn 0.262465 0.920526 -0.289385 +vn 0.289194 0.907370 -0.305036 +vn 0.213933 -0.912750 -0.348024 +vn -0.199785 -0.972457 0.120053 +vn 0.466395 -0.879475 -0.094868 +vn 0.755182 0.622048 0.206776 +vn 0.721886 0.499697 -0.478731 +vn -0.999983 -0.005766 -0.000375 +vn 0.307787 0.201663 -0.929838 +vn 0.460246 -0.885385 0.065320 +vn -0.517961 -0.612454 0.597174 +vn -0.618675 0.092248 0.780213 +vn -0.336810 0.443527 0.830568 +vn -0.552221 0.000966 0.833697 +vn 0.140478 0.706015 0.694125 +vn 0.137038 0.851981 -0.505320 +vn 0.803874 0.142663 0.577438 +vn 0.197897 0.846458 0.494313 +vn -0.161509 0.616308 0.770765 +vn 0.066699 0.071461 0.995211 +vn -0.231361 0.077626 0.969766 +vn 0.149644 -0.745680 0.649283 +vn -0.181384 -0.549229 0.815750 +vn 0.073564 -0.969292 0.234651 +vn 0.491975 -0.683054 0.539812 +vn 0.977995 0.011298 -0.208323 +vn 0.633348 0.042647 0.772691 +vn 0.614681 -0.705050 -0.353654 +vn 0.073206 -0.814163 0.576003 +vn 0.030979 -0.895807 -0.443362 +vn 0.208154 -0.882780 -0.421154 +vn 0.439375 -0.800395 -0.407820 +vn 0.582623 0.611842 -0.534977 +vn 0.579112 -0.082380 -0.811075 +vn 0.464529 0.834068 0.297563 +vn 0.049474 0.768221 -0.638270 +vn 0.043430 0.920344 0.388691 +vn 0.122736 0.362117 0.924017 +vn 0.138333 -0.330887 0.933476 +vn 0.044088 0.392670 0.918622 +vn -0.081609 0.701984 0.707501 +vn 0.039600 -0.075987 -0.996322 +vn 0.308201 0.048409 -0.950089 +vn 0.081956 0.080713 0.993362 +vn 0.712358 -0.547479 -0.439105 +vn 0.456675 -0.878326 0.141390 +vn 0.225448 0.599196 0.768204 +vn -0.161668 0.581148 0.797578 +vn -0.133581 0.402364 0.905682 +vn 0.068210 0.698697 0.712159 +vn 0.468068 0.868346 0.163976 +vn 0.332674 0.930704 0.152045 +vn 0.295560 0.804015 -0.515949 +vn 0.127415 0.886163 -0.445512 +vn -0.061204 0.690798 -0.720452 +vn -0.104451 0.823005 -0.558348 +vn -0.466653 0.677410 -0.568640 +vn -0.355711 0.820971 -0.446627 +vn -0.773119 0.625655 0.104126 +vn -0.653752 0.743207 0.142307 +vn -0.519526 0.414551 0.747154 +vn -0.402484 0.592776 0.697584 +vn 0.337668 0.904150 0.261713 +vn -0.045363 0.937179 0.345886 +vn -0.000347 0.844912 0.534905 +vn 0.170593 0.968869 0.179416 +vn 0.482917 0.767163 -0.422200 +vn 0.347540 0.825622 -0.444482 +vn 0.210532 0.356347 -0.910326 +vn 0.057303 0.476027 -0.877562 +vn -0.167315 0.182115 -0.968937 +vn -0.186271 0.380868 -0.905672 +vn -0.541974 0.284425 -0.790801 +vn -0.417259 0.459652 -0.783973 +vn -0.752292 0.632874 -0.183106 +vn -0.628318 0.744565 -0.225476 +vn -0.410330 0.797278 0.442694 +vn -0.299988 0.909995 0.286210 +vn 0.341131 0.769478 0.539939 +vn -0.043804 0.791775 0.609240 +vn -0.013231 0.646629 0.762690 +vn 0.182479 0.862247 0.472474 +vn 0.528228 0.837333 -0.140884 +vn 0.396355 0.905048 -0.154242 +vn 0.279304 0.601370 -0.748561 +vn 0.126022 0.712240 -0.690531 +vn -0.099739 0.466468 -0.878897 +vn -0.118367 0.639461 -0.759657 +vn -0.484460 0.527137 -0.698158 +vn -0.355416 0.688660 -0.632002 +vn -0.724227 0.689271 -0.020046 +vn -0.594821 0.803525 -0.023141 +vn -0.415904 0.645438 0.640651 +vn -0.294189 0.794543 0.531182 +vn 0.478686 -0.877263 0.035629 +vn 0.266773 -0.846720 -0.460323 +vn 0.068874 -0.442522 -0.894109 +vn -0.051446 -0.009167 -0.998634 +vn 0.125940 0.057112 -0.990393 +vn -0.036317 0.557234 -0.829561 +vn 0.050621 0.862174 -0.504076 +vn 0.034880 0.958356 -0.283439 +vn 0.038017 0.997237 0.063819 +vn 0.008136 0.931387 0.363940 +vn 0.452122 -0.471036 0.757437 +vn 0.558909 -0.825146 -0.082189 +vn 0.947104 -0.317787 -0.044786 +vn 0.040794 -0.527046 0.848857 +vn -0.014013 0.401274 0.915851 +vn -0.044131 0.313982 0.948403 +vn -0.055028 0.975017 0.215207 +vn 0.121188 0.976374 0.178904 +vn 0.088085 0.371502 -0.924244 +vn 0.332763 0.932080 0.143166 +vn 0.245504 0.927402 0.282230 +vn 0.183684 0.935125 0.302986 +vn 0.282102 0.955166 0.089871 +vn 0.220061 0.962148 0.160762 +vn 0.129130 0.991586 0.009126 +vn 0.057279 0.321976 0.945014 +vn 0.099587 -0.992808 -0.066436 +vn 0.024294 -0.504476 0.863084 +vn 0.031677 0.311433 0.949740 +vn 0.244470 0.824122 -0.510938 +vn -0.091016 0.433957 -0.896325 +vn 0.000630 0.981054 0.193735 +vn 0.340224 0.412597 0.844992 +vn 0.215355 -0.553137 -0.804775 +vn 0.525164 -0.838745 -0.143912 +vn -0.041870 0.437354 -0.898314 +vn 0.002225 -0.333356 -0.942798 +vn 0.019235 -0.385362 -0.922565 +vn 0.341305 0.416337 -0.842719 +vn 0.439038 -0.372221 -0.817739 +vn 0.519101 -0.854061 0.033373 +vn 0.034102 -0.368509 0.928998 +vn 0.484820 -0.870548 0.084231 +vn 0.074633 -0.996580 -0.035477 +vn 0.022782 -0.468221 -0.883318 +vn 0.049254 -0.991709 -0.118690 +vn -0.176780 0.969432 0.170151 +vn 0.737213 0.526958 0.422885 +vn 0.771128 0.537986 -0.340488 +vn -0.104822 0.988953 -0.104803 +vn -0.153101 0.907825 -0.390402 +vn 0.073032 0.235928 -0.969022 +vn -0.947104 -0.317785 -0.044790 +vn -0.737215 0.526956 0.422885 +vn -0.771127 0.537990 -0.340486 +vn -0.452123 -0.471035 0.757437 +vn -0.558911 -0.825144 -0.082191 +vn -0.040793 -0.527047 0.848857 +vn -0.099585 -0.992808 -0.066441 +vn -0.071090 0.325374 0.942910 +vn 0.025312 -0.410914 0.911323 +vn 0.100372 -0.994700 0.022312 +vn 0.501624 -0.863674 0.049395 +vn 0.371023 -0.505571 -0.778935 +vn 0.937609 -0.347552 0.009794 +vn 0.760757 0.533072 -0.370249 +vn -0.029598 0.999547 0.005559 +vn -0.017779 0.444107 0.895798 +vn 0.013441 0.999872 -0.008668 +vn 0.322553 0.431861 0.842292 +vn 0.736072 0.593027 0.326371 +vn 0.091014 0.433952 -0.896327 +vn 0.041869 0.437351 -0.898316 +vn -0.019233 -0.385361 -0.922565 +vn -0.341305 0.416339 -0.842718 +vn -0.439038 -0.372221 -0.817739 +vn 0.014013 0.401273 0.915851 +vn -0.000632 0.981055 0.193729 +vn -0.340226 0.412602 0.844989 +vn 0.055029 0.975016 0.215210 +vn 0.044131 0.313982 0.948403 +vn 0.353152 -0.393848 0.848627 +vn 0.038184 -0.490292 -0.870722 +vn -0.004879 0.317922 -0.948105 +vn -0.041307 0.301211 -0.952663 +vn 0.349772 0.316490 -0.881756 +vn 0.052144 -0.985729 0.160063 +vn -0.002850 -0.630404 -0.776262 +vn 0.069478 0.210791 -0.975059 +vn 0.004606 0.229448 -0.973310 +vn 0.055384 0.928896 -0.366176 +vn 0.033262 0.958796 -0.282142 +vn -0.011431 0.562422 0.826771 +vn 0.354281 0.499223 0.790735 +vn 0.374044 -0.276519 0.885228 +vn 0.003390 -0.233125 0.972441 +vn -0.011074 0.529686 0.848121 +vn 0.051273 -0.149628 0.987412 +vn 0.115731 0.513046 0.850523 +vn 0.720848 0.414038 -0.555833 +vn 0.365933 -0.596388 -0.714433 +vn 0.293768 0.274571 -0.915594 +vn 0.942770 -0.328877 0.055003 +vn 0.782367 0.588074 0.205115 +vn 0.007309 0.248430 -0.968622 +vn 0.018018 -0.625047 -0.780379 +vn 0.142527 0.898148 -0.415953 +vn 0.265776 0.827138 -0.495184 +vn 0.044020 -0.978228 0.202810 +vn 0.504978 -0.851685 0.140107 +vn -0.979706 0.082305 -0.182760 +vn -0.978803 0.090456 -0.183748 +vn -0.981556 0.089961 -0.168687 +vn -0.999701 0.021121 -0.012331 +vn -0.999969 0.006333 -0.004599 +vn -0.906865 -0.035651 0.419911 +vn -0.911528 -0.047134 0.408529 +vn -0.637248 -0.086789 0.765757 +vn -0.641485 -0.095758 0.761136 +vn -0.300014 -0.103636 0.948289 +vn -0.306266 -0.106425 0.945978 +vn 0.057881 -0.112549 0.991959 +vn 0.061592 -0.116008 0.991337 +vn 0.403193 -0.110484 0.908421 +vn 0.433041 -0.106222 0.895093 +vn 0.735625 -0.050852 0.675477 +vn 0.756833 -0.042637 0.652217 +vn 0.938387 -0.017261 0.345156 +vn 0.943497 -0.021232 0.330701 +vn 0.998747 -0.050023 -0.001803 +vn 0.998759 -0.049645 0.004025 +vn 0.978034 -0.019312 -0.207547 +vn 0.980772 -0.016112 -0.194494 +vn 0.948283 -0.011110 -0.317231 +vn -0.083734 0.991898 -0.095533 +vn -0.543136 0.815888 -0.198317 +vn -0.325858 0.945126 0.023530 +vn 0.000211 0.963153 -0.268952 +vn -0.011566 0.993128 -0.116458 +vn 0.085892 0.991870 -0.093892 +vn -0.010312 0.999537 0.028628 +vn 0.295941 0.955202 0.002781 +vn -0.016722 0.978484 0.205645 +vn 0.212544 0.964839 0.154629 +vn 0.250538 0.811536 0.527863 +vn 0.615616 0.676612 0.403996 +vn 0.748650 0.326221 0.577151 +vn 0.814621 0.565404 0.129276 +vn 0.947264 0.257090 0.191299 +vn 0.847040 0.492243 -0.200551 +vn 0.957938 0.208307 -0.197392 +vn 0.841157 0.408408 -0.354482 +vn 0.910659 0.187684 -0.368070 +vn 0.590100 0.348594 -0.728192 +vn 0.556928 0.071592 -0.827469 +vn 0.000888 0.382814 -0.923825 +vn -0.006567 0.036725 -0.999304 +vn -0.555191 0.371441 -0.744174 +vn 0.015529 0.424163 0.905453 +vn -0.304389 -0.122117 0.944688 +vn 0.051256 -0.145925 0.987967 +vn -0.342471 0.416374 0.842227 +vn -0.245249 0.822276 0.513532 +vn -0.632053 0.682046 0.367863 +vn -0.224396 0.960514 0.164499 +vn -0.545173 0.836695 0.052234 +vn -0.681284 0.728889 -0.067619 +vn -0.940711 0.298826 -0.160515 +vn -0.629924 0.704439 -0.327050 +vn -0.872389 0.361913 -0.328567 +vn -0.534264 0.137203 -0.834109 +vn -0.003514 -0.316976 -0.948427 +vn 0.381027 -0.329237 -0.863957 +vn 0.359542 -0.542821 -0.758996 +vn 0.568501 -0.600757 -0.562048 +vn -0.003458 -0.987292 -0.158882 +vn -0.014668 -0.949072 -0.314718 +vn 0.000689 -0.935831 -0.352448 +vn -0.008472 -0.988765 -0.149238 +vn -0.000562 -0.999950 -0.009953 +vn -0.000528 -0.999954 -0.009574 +vn 0.001192 -0.999889 0.014859 +vn 0.001189 -0.999916 0.012902 +vn 0.005462 -0.997890 0.064704 +vn 0.005725 -0.998119 0.061044 +vn 0.010420 -0.993963 0.109222 +vn -0.514852 -0.567870 0.642224 +vn -0.235917 -0.552745 0.799260 +vn -0.621604 -0.184782 0.761226 +vn -0.756152 0.332694 0.563514 +vn -0.903228 -0.086922 0.420267 +vn -0.961543 0.250522 0.112575 +vn -0.965482 -0.253949 0.057921 +vn -0.939640 -0.276672 -0.201321 +vn -0.763905 -0.629922 -0.140174 +vn -0.887289 -0.439752 -0.139056 +vn 0.964279 -0.171606 -0.201784 +vn 0.973740 -0.224861 0.035604 +vn 0.911499 -0.070272 0.405255 +vn 0.733573 -0.194244 0.651260 +vn 0.403543 -0.140020 0.904183 +vn 0.345847 -0.547182 0.762221 +vn 0.049049 -0.539403 0.840618 +vn -0.004565 -0.548273 -0.836287 +vn -0.349902 -0.312025 -0.883294 +vn -0.291869 -0.573747 -0.765263 +vn -0.790648 -0.134259 -0.597370 +vn -0.623531 -0.640991 -0.447593 +vn -0.960073 -0.255129 -0.114760 +vn -0.798772 -0.591990 -0.107286 +vn 0.713707 -0.174058 -0.678474 +vn 0.914177 -0.279396 -0.293629 +vn 0.669446 -0.729927 -0.138016 +vn 0.794820 -0.573692 -0.197834 +vn 0.738609 0.000177 -0.674134 +vn 0.744976 -0.000236 -0.667092 +vn 0.960649 -0.046872 -0.273781 +vn 0.452992 0.010548 -0.891452 +vn 0.458731 0.012171 -0.888492 +vn 0.004351 0.025247 -0.999672 +vn 0.008641 0.026035 -0.999624 +vn -0.396628 0.018564 -0.917792 +vn -0.398001 0.022343 -0.917113 +vn 0.319435 0.772165 -0.549292 +vn 0.668228 0.668725 -0.326004 +vn 0.448704 0.869269 -0.207452 +vn -0.965197 0.176445 -0.193034 +vn -0.944709 0.167774 -0.281737 +vn -0.863955 0.448613 -0.228755 +vn -0.955072 0.165049 -0.246162 +vn -0.836708 0.543861 0.064311 +vn 0.343662 0.420940 0.839468 +vn -0.020496 0.842019 0.539059 +vn -0.972739 -0.148394 -0.178208 +vn -0.834077 -0.551399 -0.016617 +vn -0.772718 -0.536630 0.339020 +vn -0.000078 -0.999710 0.024087 +vn -0.000156 -0.999480 0.032231 +vn -0.000079 -0.999487 0.032043 +vn -0.000147 -0.999669 0.025734 +vn 0.000001 -1.000000 0.000000 +vn 0.000001 -1.000000 -0.000000 +vn 0.000018 -0.999995 -0.003177 +vn -0.329703 0.773241 -0.541659 +vn 0.735980 -0.643442 -0.210513 +vn 0.597576 0.797110 -0.086707 +vn 0.522032 0.848811 0.083681 +vn 0.983334 -0.162625 -0.081292 +vn 0.976851 -0.204189 -0.063785 +vn 0.962191 -0.021388 -0.271536 +vn -0.998790 -0.045029 -0.019781 +vn -0.983798 0.059055 -0.169278 +vn -0.996493 -0.083566 -0.004372 +vn -0.982580 0.077272 -0.169012 +vn 0.008183 -0.992073 0.125400 +vn 0.000000 -1.000000 0.000000 +vn -0.793560 0.049952 -0.606438 +vn -0.801351 0.034031 -0.597225 +vn 0.816429 -0.577435 0.003554 +vn 0.000048 -0.999959 -0.009090 +vn 0.001158 -0.975480 -0.220084 +vn 0.638260 -0.525039 0.562991 +vn 0.794415 -0.524618 0.306074 +vn -0.003407 -0.072575 0.997357 +vn -0.002568 -0.078178 0.996936 +vn -0.003496 -0.071975 0.997400 +vn -0.002449 -0.078974 0.996874 +vn 0.000075 0.601181 0.799113 +vn 0.061067 0.742447 0.667116 +vn 0.000027 0.797826 0.602887 +vn 0.192936 0.360754 0.912487 +vn -0.000000 -0.219295 0.975659 +vn 0.258842 -0.113580 0.959219 +vn 0.330278 -0.536263 0.776749 +vn -0.034003 -0.776823 0.628800 +vn -0.000001 -0.716958 0.697116 +vn 0.034003 -0.776823 0.628800 +vn 0.084550 -0.958449 0.272446 +vn -0.328396 -0.536395 0.777455 +vn -0.258083 -0.113627 0.959418 +vn -0.192251 0.360527 0.912721 +vn -0.061554 0.742242 0.667299 +vn 0.000000 -0.943224 0.332157 +vn -0.084550 -0.958449 0.272446 +vn -0.261378 0.401054 0.877973 +vn -0.414118 -0.178692 0.892511 +vn -0.692854 -0.607368 0.388662 +vn -0.295045 -0.863047 0.409999 +vn -0.253412 -0.947005 0.197392 +vn -0.337134 -0.033826 -0.940849 +vn -0.396882 0.136422 -0.907675 +vn -0.382598 0.012609 -0.923829 +vn -0.340196 -0.078021 -0.937112 +vn 0.000542 -0.132017 -0.991247 +vn -0.246841 -0.126217 -0.960801 +vn 0.000023 -0.225956 -0.974137 +vn 0.386790 -0.815175 0.431142 +vn 0.683040 -0.720472 0.119903 +vn 0.265888 -0.907525 0.325118 +vn 0.696248 -0.605228 0.385925 +vn 0.413204 -0.176729 0.893325 +vn 0.255159 -0.946582 0.197171 +vn 0.296744 -0.862608 0.409695 +vn -0.402494 -0.808767 0.428829 +vn -0.679746 -0.723495 0.120413 +vn -0.273057 -0.905565 0.324641 +vn 0.246298 -0.126937 -0.960846 +vn 0.340033 -0.081347 -0.936888 +vn 0.336307 -0.032060 -0.941207 +vn 0.261676 0.401301 0.877772 +vn 0.394836 0.135476 -0.908708 +vn 0.382005 0.022245 -0.923893 +vn 0.015604 0.899012 0.437646 +vn -0.015063 0.899221 0.437235 +vn 0.033175 0.907230 0.419326 +vn -0.036844 0.754918 0.654784 +vn 0.148243 0.902792 0.403722 +vn -0.044896 0.765310 0.642094 +vn 0.263116 0.890124 0.372088 +vn 0.034232 0.784278 0.619464 +vn 0.404796 0.823324 0.397842 +vn 0.088751 0.778198 0.621716 +vn -0.688205 0.538712 0.485967 +vn -0.455827 0.529092 0.715739 +vn -0.820718 0.240926 0.518050 +vn -0.627000 0.103909 0.772058 +vn -0.786027 -0.165653 0.595584 +vn -0.637917 -0.056849 0.768004 +vn -0.642671 -0.572632 0.508986 +vn -0.773936 -0.401198 0.489962 +vn -0.740554 -0.658013 0.136376 +vn -0.867114 -0.442728 0.228267 +vn -0.033521 0.907206 0.419349 +vn 0.036557 0.754739 0.655006 +vn 0.193572 0.409937 0.891337 +vn 0.400016 0.092458 0.911833 +vn 0.501973 -0.433076 0.748644 +vn 0.637917 -0.056851 0.768004 +vn 0.812634 -0.349994 0.465973 +vn 0.773935 -0.401196 0.489966 +vn 0.867112 -0.442730 0.228270 +vn 0.740555 -0.658013 0.136373 +vn 0.044894 0.765308 0.642097 +vn -0.263081 0.890118 0.372127 +vn -0.148259 0.902786 0.403729 +vn -0.034209 0.784268 0.619479 +vn 0.359998 0.373727 0.854827 +vn 0.358628 0.432750 0.827111 +vn 0.627002 0.103910 0.772056 +vn 0.786029 -0.165654 0.595582 +vn 0.820719 0.240927 0.518049 +vn 0.982102 -0.038593 0.184357 +vn 0.929823 0.297605 0.216475 +vn 0.978452 -0.155406 -0.135941 +vn 0.960153 0.239637 -0.143806 +vn -0.502229 -0.861695 0.072441 +vn -0.846238 -0.486932 0.216285 +vn -0.982101 -0.038592 0.184359 +vn -0.929822 0.297606 0.216474 +vn -0.960153 0.239639 -0.143806 +vn -0.194152 0.410307 0.891040 +vn -0.359998 0.373727 0.854827 +vn -0.358630 0.432748 0.827112 +vn -0.401284 0.093137 0.911206 +vn -0.500187 -0.438625 0.746606 +vn -0.127518 -0.823947 0.552132 +vn -0.002053 -0.962354 0.271793 +vn -0.542498 -0.703709 0.458791 +vn -0.812634 -0.349992 0.465973 +vn 0.831132 -0.555822 -0.016772 +vn 0.846238 -0.486932 0.216284 +vn 0.642672 -0.572634 0.508983 +vn 0.521177 -0.821385 0.231736 +vn 0.552896 -0.697324 0.456120 +vn 0.130062 -0.821913 0.554565 +vn 0.363148 -0.157237 -0.918368 +vn 0.295606 -0.059115 -0.953479 +vn 0.283761 0.047340 -0.957726 +vn 0.358724 -0.055054 -0.931819 +vn 0.593351 -0.146501 -0.791500 +vn 0.435017 0.088239 -0.896088 +vn 0.623337 -0.018962 -0.781724 +vn -0.363147 -0.157237 -0.918369 +vn -0.593350 -0.146500 -0.791501 +vn -0.706339 0.082916 -0.703001 +vn -0.358724 -0.055052 -0.931819 +vn -0.295595 -0.058256 -0.953536 +vn -0.306059 -0.043260 -0.951029 +vn -0.978452 -0.155406 -0.135943 +vn -0.831131 -0.555824 -0.016771 +vn 0.688204 0.538711 0.485969 +vn 0.455831 0.529090 0.715739 +vn -0.404781 0.823327 0.397851 +vn -0.088752 0.778198 0.621717 +vn 0.306915 0.276675 -0.910634 +vn 0.302843 -0.041781 -0.952124 +vn 0.674866 -0.030975 -0.737290 +vn 0.642479 -0.073604 -0.762760 +vn 0.670107 0.135937 -0.729711 +vn -0.674867 -0.030975 -0.737289 +vn -0.623337 -0.018962 -0.781723 +vn -0.670107 0.135938 -0.729711 +vn -0.642492 -0.073601 -0.762749 +vn -0.318886 0.210701 -0.924076 +vn -0.435016 0.088238 -0.896089 +vn -0.510468 -0.827636 0.233328 +vn 0.502231 -0.861694 0.072437 +vn -0.000450 -0.962134 0.272578 +vn 0.706339 0.082918 -0.703000 +vn -0.283763 0.047341 -0.957725 +vn 0.931808 -0.310741 -0.187544 +vn 0.751837 -0.644724 -0.138101 +vn 0.886525 -0.445562 -0.124690 +vn 0.809678 -0.586847 -0.005603 +vn 0.958856 -0.278348 0.055831 +vn 0.759818 -0.553909 0.340385 +vn 0.897843 -0.130278 0.420603 +vn 0.531483 -0.572532 0.624286 +vn 0.619616 -0.211315 0.755925 +vn 0.245838 -0.560285 0.790977 +vn 0.305047 -0.129937 0.943431 +vn -0.043682 -0.539795 0.840663 +vn -0.046624 -0.145814 0.988213 +vn -0.334634 -0.542032 0.770858 +vn -0.399718 -0.130354 0.907322 +vn -0.628391 -0.518810 0.579622 +vn -0.736405 -0.158984 0.657595 +vn -0.809110 -0.499829 0.309051 +vn -0.913002 -0.033259 0.406598 +vn -0.828341 -0.559808 0.021574 +vn -0.981950 -0.185338 0.037749 +vn -0.794783 -0.564463 -0.222940 +vn -0.965985 -0.116811 -0.230711 +vn -0.644430 -0.750129 -0.148380 +vn -0.930474 -0.236926 -0.279434 +vn -0.740644 -0.643777 -0.192345 +vn -0.571627 -0.633305 -0.521698 +vn 0.985488 0.080439 -0.149479 +vn 0.985087 0.087522 -0.148132 +vn 0.987173 0.086965 -0.133888 +vn 0.999841 0.017232 -0.004501 +vn 0.999962 0.001957 -0.008456 +vn 0.912687 -0.041401 0.406556 +vn 0.909290 -0.053818 0.412668 +vn 0.651665 -0.093715 0.752695 +vn 0.644293 -0.103119 0.757795 +vn 0.317388 -0.109171 0.941991 +vn 0.310055 -0.112036 0.944094 +vn -0.058473 -0.116924 0.991418 +vn -0.055428 -0.119788 0.991251 +vn -0.419458 -0.109502 0.901146 +vn -0.391278 -0.109428 0.913743 +vn -0.754410 -0.043281 0.654975 +vn -0.734167 -0.043589 0.677569 +vn -0.943044 -0.013006 0.332415 +vn -0.934314 -0.018580 0.355968 +vn -0.998840 -0.046952 0.010666 +vn -0.998877 -0.047385 0.000513 +vn -0.973289 -0.014320 -0.229136 +vn -0.970182 -0.009312 -0.242200 +vn -0.935430 -0.004557 -0.353482 +vn -0.676702 0.662986 -0.320194 +vn -0.317744 0.771406 -0.551337 +vn -0.836864 0.408351 -0.364567 +vn -0.000760 0.963125 -0.269054 +vn -0.454989 0.867379 -0.201591 +vn -0.095781 0.990821 -0.095388 +vn -0.306246 0.951947 0.003335 +vn 0.011504 0.993114 -0.116589 +vn 0.012741 0.999306 0.035019 +vn 0.088208 0.991259 -0.098104 +vn 0.325995 0.944912 0.029454 +vn 0.537525 0.818129 -0.204284 +vn 0.686518 0.724022 -0.066973 +vn 0.941540 0.294016 -0.164493 +vn 0.860797 0.446682 -0.243935 +vn 0.965245 0.093047 -0.244224 +vn 0.973741 0.190117 0.125235 +vn 0.976236 -0.154089 -0.152383 +vn 0.968884 0.161329 -0.187713 +vn 0.945415 0.160273 -0.283732 +vn 0.878658 0.359021 -0.314745 +vn 0.548910 0.376334 -0.746372 +vn 0.328592 0.774560 -0.540448 +vn -0.012633 0.383280 -0.923546 +vn -0.617137 0.337181 -0.710951 +vn -0.585801 0.103047 -0.803877 +vn -0.907994 0.195299 -0.370683 +vn -0.722223 -0.164994 -0.671693 +vn -0.354659 -0.555373 -0.752182 +vn -0.395353 -0.322372 -0.860100 +vn -0.021528 -0.313035 -0.949498 +vn -0.017835 0.037704 -0.999130 +vn 0.333406 -0.320890 -0.886493 +vn 0.524814 0.119459 -0.842793 +vn 0.779762 -0.144814 -0.609098 +vn 0.950622 -0.280677 -0.132431 +vn 0.790028 0.031381 -0.612267 +vn 0.796434 0.047354 -0.602869 +vn 0.984788 0.048899 -0.166739 +vn 0.377015 0.021346 -0.925961 +vn 0.377302 0.017864 -0.925918 +vn -0.007699 0.026672 -0.999615 +vn -0.009327 0.026259 -0.999612 +vn -0.474084 0.014669 -0.880357 +vn -0.478721 0.012918 -0.877872 +vn -0.745444 0.004051 -0.666555 +vn -0.741538 0.004179 -0.670898 +vn -0.963319 -0.015955 -0.267884 +vn -0.961927 -0.042403 -0.269998 +vn -0.600845 0.794603 -0.087128 +vn -0.526433 0.846283 0.081684 +vn -0.215318 0.964222 0.154642 +vn -0.613499 0.679029 0.403162 +vn -0.232848 0.817891 0.526152 +vn -0.340050 0.425351 0.838715 +vn -0.008471 0.419405 0.907760 +vn 0.000866 -0.989166 -0.146798 +vn 0.012962 -0.941457 -0.336884 +vn -0.006463 -0.954965 -0.296647 +vn 0.008595 -0.986400 -0.164139 +vn 0.000468 -0.999959 -0.009001 +vn 0.000528 -0.999946 -0.010418 +vn -0.001117 -0.999891 0.014749 +vn -0.001162 -0.999911 0.013321 +vn -0.005004 -0.998027 0.062590 +vn -0.005833 -0.997840 0.065435 +vn -0.010826 -0.992792 0.119360 +vn 0.794372 -0.596693 -0.113708 +vn 0.600233 -0.631117 -0.491337 +vn 0.284804 -0.563770 -0.775274 +vn -0.030391 -0.547620 -0.836175 +vn 0.352425 0.401196 0.845481 +vn 0.769018 0.301100 0.563871 +vn 0.266384 0.817156 0.511171 +vn 0.636541 0.677324 0.368847 +vn 0.224876 0.959996 0.166852 +vn 0.550972 0.832506 0.057999 +vn 0.000187 -0.999692 0.024812 +vn 0.000295 -0.999484 0.032107 +vn 0.000219 -0.999478 0.032293 +vn 0.000250 -0.999691 0.024874 +vn -0.000000 -1.000000 -0.000000 +vn 0.000000 -1.000000 -0.000000 +vn -0.000052 -0.999985 -0.005482 +vn -0.000050 -0.999987 -0.005188 +vn -0.849471 0.490696 -0.193950 +vn -0.823259 0.556360 0.112730 +vn -0.942351 0.261892 -0.208297 +vn -0.936327 0.303173 0.177139 +vn -0.737163 0.353649 0.575781 +vn 0.621527 0.711197 -0.328485 +vn 0.829370 0.551692 0.088213 +vn 0.010713 0.978315 0.206847 +vn 0.012337 0.842837 0.538027 +vn 0.998371 -0.052322 -0.022770 +vn 0.995806 -0.091174 -0.007587 +vn 0.983050 0.081352 -0.164301 +vn 0.007356 -0.078704 0.996871 +vn 0.006822 -0.075093 0.997153 +vn 0.007407 -0.079048 0.996843 +vn 0.006750 -0.074609 0.997190 +vn -0.984554 -0.156568 -0.078354 +vn -0.978269 -0.198231 -0.060776 +vn -0.006306 -0.994591 0.103679 +vn 0.000000 -1.000000 0.000000 +vn -0.002102 -0.975598 -0.219555 +vn -0.352349 -0.898504 0.261801 +vn 0.667650 -0.557052 0.493899 +vn -0.439515 -0.891389 0.110691 +vn 0.825477 -0.507658 0.246720 +vn 0.806384 -0.591195 -0.015314 +vn 0.972631 -0.134456 -0.189500 +vn 0.837985 -0.320611 -0.441577 +vn 0.841850 0.015679 -0.539483 +vn 0.694847 -0.382081 -0.609263 +vn 0.724935 -0.181379 -0.664508 +vn 0.456685 -0.350954 -0.817478 +vn 0.469841 -0.124697 -0.873899 +vn 0.177163 -0.269704 -0.946506 +vn 0.181863 -0.000412 -0.983324 +vn 0.000000 -0.294736 -0.955579 +vn -0.000000 -0.032993 -0.999456 +vn -0.181863 -0.000410 -0.983324 +vn -0.164619 0.338856 -0.926324 +vn -0.458313 0.145151 -0.876858 +vn -0.400266 0.431409 -0.808501 +vn -0.656901 0.369278 -0.657355 +vn -0.540789 0.647716 -0.536667 +vn -0.503568 0.646710 -0.572874 +vn -0.411954 0.731196 -0.543735 +vn -0.542184 0.585218 -0.602956 +vn -0.382931 0.634444 -0.671450 +vn -0.590344 0.661374 -0.462686 +vn -0.406281 0.707284 -0.578520 +vn -0.587957 0.734556 -0.338724 +vn -0.374859 0.770600 -0.515419 +vn -0.541199 0.807022 -0.236261 +vn -0.327725 0.831196 -0.449121 +vn -0.390484 0.906134 -0.162612 +vn -0.214789 0.880787 -0.421995 +vn -0.211573 0.971024 -0.111124 +vn -0.125886 0.913087 -0.387847 +vn 0.000000 0.996397 -0.084814 +vn 0.000000 0.923026 -0.384739 +vn 0.125886 0.913087 -0.387848 +vn 0.079452 0.841563 -0.534285 +vn 0.214789 0.880787 -0.421995 +vn 0.160647 0.803314 -0.573480 +vn 0.327725 0.831196 -0.449121 +vn 0.374854 0.770603 -0.515417 +vn 0.541199 0.807022 -0.236260 +vn 0.587957 0.734557 -0.338723 +vn 0.697374 0.716377 0.021778 +vn 0.748228 0.649586 -0.134883 +vn 0.781546 0.563994 0.266640 +vn 0.873366 0.479962 0.082873 +vn 0.821105 0.331869 0.464381 +vn 0.924300 0.286049 0.252677 +vn 0.778106 0.055817 0.625648 +vn 0.917927 0.033195 0.395359 +vn 0.680677 -0.258899 0.685311 +vn 0.818036 -0.356537 0.451330 +vn 0.573294 -0.501167 0.648202 +vn 0.992932 -0.040047 0.111723 +vn 0.934192 0.186187 -0.304337 +vn 0.766605 0.273747 -0.580844 +vn 0.704939 0.102228 -0.701862 +vn 0.458315 0.145155 -0.876856 +vn 0.164619 0.338855 -0.926325 +vn -0.000001 0.315858 -0.948807 +vn -0.122857 0.626186 -0.769933 +vn -0.307529 0.711097 -0.632271 +vn -0.371939 0.860571 -0.347964 +vn -0.253005 0.812671 -0.524932 +vn -0.217821 0.736551 -0.640348 +vn -0.330720 -0.851491 0.406925 +vn 0.694470 -0.686774 -0.214601 +vn -0.244711 -0.874565 0.418632 +vn 0.612649 -0.626721 -0.481541 +vn 0.331915 -0.812110 -0.479906 +vn 0.417116 -0.557084 -0.718103 +vn 0.160812 -0.612867 -0.773650 +vn 0.171932 -0.450093 -0.876274 +vn 0.000000 -0.618842 -0.785516 +vn 0.000000 -0.465098 -0.885260 +vn -0.171932 -0.450092 -0.876274 +vn -0.177162 -0.269704 -0.946506 +vn -0.456685 -0.350957 -0.817477 +vn -0.469840 -0.124696 -0.873900 +vn -0.724935 -0.181379 -0.664508 +vn -0.704939 0.102229 -0.701862 +vn -0.766603 0.273752 -0.580844 +vn -0.605118 0.529375 -0.594637 +vn -0.848617 0.352828 -0.394159 +vn -0.685500 0.516665 -0.512978 +vn -0.898944 0.411093 -0.151337 +vn -0.750602 0.576487 -0.322894 +vn 0.966055 0.257410 -0.021863 +vn 0.848617 0.352829 -0.394160 +vn 0.605118 0.529376 -0.594638 +vn 0.656900 0.369278 -0.657355 +vn 0.400266 0.431411 -0.808500 +vn 0.122857 0.626186 -0.769933 +vn 0.000000 0.615701 -0.787980 +vn -0.086243 0.872143 -0.481590 +vn -0.209835 0.932722 -0.293257 +vn 0.898943 0.411094 -0.151336 +vn 0.685494 0.516671 -0.512980 +vn 0.503567 0.646711 -0.572874 +vn 0.540789 0.647717 -0.536666 +vn 0.307530 0.711097 -0.632271 +vn 0.086243 0.872143 -0.481589 +vn 0.000000 0.861423 -0.507889 +vn -0.052244 0.981579 -0.183774 +vn -0.094039 0.984062 -0.150925 +vn -0.147892 0.867953 -0.474116 +vn 0.000000 0.994029 -0.109113 +vn -0.195915 -0.719698 0.666072 +vn 0.132121 -0.726366 -0.674489 +vn 0.000000 -0.640395 0.768046 +vn 0.000000 -0.745144 -0.666904 +vn -0.132120 -0.726367 -0.674489 +vn -0.160811 -0.612866 -0.773650 +vn -0.331915 -0.812110 -0.479906 +vn -0.417116 -0.557082 -0.718104 +vn -0.612649 -0.626721 -0.481541 +vn -0.694846 -0.382083 -0.609263 +vn -0.837985 -0.320612 -0.441575 +vn -0.841851 0.015679 -0.539482 +vn -0.972631 -0.134456 -0.189500 +vn -0.934191 0.186191 -0.304336 +vn -0.992932 -0.040047 0.111723 +vn -0.966055 0.257411 -0.021864 +vn -0.667650 -0.557052 0.493899 +vn 0.352349 -0.898504 0.261801 +vn 0.439515 -0.891389 0.110691 +vn -0.825477 -0.507658 0.246720 +vn -0.818036 -0.356537 0.451329 +vn -0.917927 0.033194 0.395359 +vn -0.924300 0.286050 0.252677 +vn -0.873367 0.479961 0.082875 +vn -0.748228 0.649586 -0.134883 +vn 0.750601 0.576488 -0.322893 +vn 0.542184 0.585218 -0.602956 +vn 0.411954 0.731196 -0.543733 +vn 0.371940 0.860572 -0.347961 +vn 0.209835 0.932722 -0.293257 +vn 0.052244 0.981579 -0.183774 +vn 0.590349 0.661371 -0.462683 +vn 0.406281 0.707283 -0.578521 +vn 0.382931 0.634443 -0.671451 +vn 0.217819 0.736551 -0.640349 +vn 0.253005 0.812672 -0.524931 +vn 0.147892 0.867953 -0.474116 +vn 0.094039 0.984062 -0.150925 +vn 0.195915 -0.719698 0.666072 +vn 0.244711 -0.874565 0.418631 +vn -0.694470 -0.686774 -0.214600 +vn -0.806383 -0.591195 -0.015314 +vn -0.251631 0.886050 0.389356 +vn 0.000000 -0.991062 0.133399 +vn -0.000000 0.906828 0.421501 +vn 0.079027 -0.985999 0.146836 +vn -0.532249 0.794935 0.291186 +vn 0.163549 -0.976871 0.137748 +vn -0.735510 0.658831 0.158011 +vn 0.239389 -0.965852 0.099115 +vn -0.904676 0.425570 0.021229 +vn 0.187276 -0.981975 0.025556 +vn -0.958786 0.261770 -0.110479 +vn 0.381620 -0.923113 -0.047213 +vn 0.291209 -0.956563 -0.013567 +vn 0.148335 -0.983662 -0.102012 +vn 0.000000 -0.994237 -0.107201 +vn -0.079027 -0.985999 0.146835 +vn -0.382435 0.275173 0.882056 +vn 0.000000 0.655735 0.754991 +vn -0.377712 0.668918 0.640221 +vn 0.000000 0.237997 0.971266 +vn 0.000000 -0.050520 0.998723 +vn 0.382435 0.275173 0.882056 +vn 0.306566 -0.031475 0.951329 +vn 0.668454 0.320586 0.671114 +vn 0.589392 0.002948 0.807842 +vn 0.000000 0.843385 -0.537309 +vn -0.079452 0.841562 -0.534285 +vn -0.052837 0.786137 -0.615790 +vn -0.093398 0.767714 -0.633950 +vn 0.000000 0.743523 -0.668711 +vn -0.123769 0.737674 -0.663715 +vn -0.306566 -0.031475 0.951329 +vn -0.521060 -0.198874 0.830027 +vn -0.256999 -0.229193 0.938841 +vn -0.589392 0.002948 0.807842 +vn -0.668454 0.320586 0.671114 +vn -0.821105 0.331868 0.464381 +vn -0.781548 0.563990 0.266642 +vn -0.658695 0.618507 0.428450 +vn -0.571523 0.804767 0.160352 +vn -0.312528 0.916880 0.248308 +vn 0.000000 0.958138 0.286306 +vn 0.312528 0.916880 0.248308 +vn 0.211573 0.971024 -0.111124 +vn 0.390484 0.906135 -0.162611 +vn 0.635007 0.748824 0.189814 +vn 0.532249 0.794935 0.291186 +vn 0.723349 0.686762 0.071587 +vn 0.251631 0.886050 0.389356 +vn 0.330510 0.889455 0.315647 +vn 0.000000 0.939802 0.341720 +vn -0.330510 0.889455 0.315647 +vn -0.573295 -0.501168 0.648201 +vn -0.680677 -0.258899 0.685310 +vn -0.778106 0.055818 0.625648 +vn 0.377712 0.668918 0.640221 +vn 0.658695 0.618507 0.428450 +vn 0.571522 0.804767 0.160352 +vn 0.000000 0.983237 -0.182334 +vn -0.160647 0.803314 -0.573480 +vn 0.093398 0.767714 -0.633950 +vn 0.123769 0.737674 -0.663715 +vn 0.052837 0.786137 -0.615790 +vn 0.000000 0.784016 -0.620740 +vn 0.000000 -0.944352 0.328937 +vn 0.000000 -0.990175 -0.139833 +vn -0.381619 -0.923113 -0.047211 +vn -0.291206 -0.956564 -0.013566 +vn 0.330720 -0.851491 0.406925 +vn -0.697374 0.716377 0.021778 +vn -0.723349 0.686761 0.071588 +vn 0.904675 0.425572 0.021230 +vn 0.958786 0.261771 -0.110477 +vn 0.735503 0.658839 0.158006 +vn -0.000000 -0.229881 0.973219 +vn 0.256999 -0.229193 0.938841 +vn -0.148335 -0.983662 -0.102013 +vn -0.163546 -0.976872 0.137747 +vn 0.000000 -0.776124 0.630581 +vn -0.187280 -0.981974 0.025564 +vn 0.521060 -0.198874 0.830028 +vn -0.239388 -0.965852 0.099111 +vn -0.635006 0.748824 0.189815 +vn 0.917766 0.017738 0.396725 +vn 0.958810 0.003900 0.284023 +vn 0.900546 0.060305 0.430558 +vn 0.953887 -0.040452 0.297429 +vn 0.923015 -0.029399 0.383638 +vn 0.973482 0.100361 0.205572 +vn 0.928642 0.090721 0.359713 +vn 0.928344 0.365784 0.066182 +vn 0.848829 0.417463 0.324367 +vn 0.934371 0.209882 0.287924 +vn 0.815069 0.169344 0.554062 +vn 0.957424 -0.134364 0.255512 +vn 0.844455 -0.127445 0.520244 +vn 0.749273 -0.527163 0.400860 +vn 0.674412 -0.134092 0.726077 +vn 0.582219 -0.492600 0.646812 +vn 0.408803 -0.502131 0.762066 +vn 0.482467 -0.680728 0.551212 +vn 0.441092 -0.551736 0.707831 +vn 0.538024 -0.687833 0.487254 +vn 0.373430 -0.607174 0.701348 +vn 0.392879 -0.830572 0.394711 +vn 0.000000 -0.664290 0.747475 +vn 0.000000 -0.921140 0.389232 +vn -0.392879 -0.830572 0.394711 +vn -0.370623 -0.917629 0.143515 +vn -0.559975 -0.793320 0.238898 +vn -0.487051 -0.872928 0.027897 +vn -0.492921 -0.861827 0.119516 +vn -0.451193 -0.888173 -0.087029 +vn -0.640604 -0.766170 -0.051084 +vn -0.627673 -0.741330 -0.237607 +vn -0.842992 -0.498154 -0.202997 +vn -0.558729 -0.742385 -0.369712 +vn -0.722650 -0.500639 -0.476589 +vn -0.595399 -0.636457 -0.490329 +vn -0.716550 -0.384528 -0.581974 +vn -0.522792 -0.452974 -0.722152 +vn -0.114261 -0.650980 -0.750446 +vn -0.392841 -0.833639 -0.388231 +vn 0.537096 -0.757037 -0.372052 +vn -0.267246 -0.587430 -0.763875 +vn -0.417399 -0.302810 -0.856787 +vn -0.149027 -0.306153 -0.940245 +vn -0.122525 0.064870 -0.990343 +vn 0.839684 -0.148748 -0.522306 +vn 0.871841 0.218341 -0.438431 +vn 0.698404 -0.212019 0.683578 +vn 0.712714 0.686765 -0.142804 +vn 0.698754 -0.139914 0.701547 +vn 0.406653 0.860707 0.306296 +vn 0.632985 -0.299999 0.713673 +vn 0.029691 0.592999 0.804655 +vn 0.602492 -0.292067 0.742765 +vn -0.143818 0.363847 0.920289 +vn 0.741240 -0.314158 0.593184 +vn 0.935786 0.067959 0.345956 +vn 0.847166 -0.158053 0.507276 +vn 0.908308 0.035636 0.416781 +vn 0.610137 -0.218613 0.761539 +vn 0.711142 0.084585 0.697942 +vn 0.650743 -0.221434 0.726292 +vn 0.686212 -0.056118 0.725233 +vn 0.625967 -0.762308 -0.164475 +vn 0.587806 -0.773852 0.235877 +vn 0.570129 -0.618898 0.540295 +vn 0.986850 -0.152081 0.054751 +vn -0.373430 -0.607174 0.701348 +vn -0.538024 -0.687833 0.487254 +vn -0.441091 -0.551736 0.707832 +vn -0.482467 -0.680728 0.551212 +vn -0.408803 -0.502131 0.762066 +vn -0.582219 -0.492600 0.646812 +vn -0.674412 -0.134092 0.726077 +vn -0.749273 -0.527163 0.400860 +vn -0.844455 -0.127445 0.520244 +vn -0.957424 -0.134364 0.255512 +vn -0.815069 0.169344 0.554062 +vn -0.934371 0.209882 0.287924 +vn -0.848829 0.417463 0.324366 +vn -0.936574 0.338331 0.091444 +vn -0.926552 0.079410 0.367689 +vn -0.970619 0.108122 0.214961 +vn -0.922512 -0.027070 0.385017 +vn -0.953887 -0.040452 0.297429 +vn -0.917766 0.017738 0.396725 +vn -0.958810 0.003900 0.284023 +vn -0.900546 0.060305 0.430558 +vn -0.953776 -0.066538 0.293060 +vn -0.866504 0.227507 -0.444311 +vn -0.897776 0.412568 -0.154225 +vn -0.770561 -0.387874 -0.505757 +vn -0.715138 -0.403393 0.570835 +vn -0.534600 -0.774839 -0.337383 +vn -0.225159 -0.900449 -0.372149 +vn -0.209061 -0.967138 -0.144696 +vn 0.210787 -0.967390 -0.140445 +vn -0.208557 -0.969731 0.126988 +vn 0.209235 -0.970340 0.121079 +vn -0.165321 -0.847029 0.505184 +vn 0.175951 -0.847094 0.501471 +vn -0.107658 -0.616227 0.780176 +vn 0.120613 -0.610933 0.782441 +vn -0.082778 -0.341536 0.936216 +vn 0.088369 -0.330708 0.939587 +vn -0.000000 -0.073567 0.997290 +vn 0.214833 -0.197629 0.956446 +vn 0.227538 0.053154 0.972318 +vn 0.516124 0.003038 0.856508 +vn 0.732422 0.235333 0.638887 +vn 0.710183 0.443645 0.546644 +vn 0.441597 0.362120 0.820891 +vn 0.417119 0.505014 0.755627 +vn 0.111154 0.658820 0.744044 +vn 0.227248 0.485056 0.844440 +vn 0.318551 0.401296 0.858771 +vn 0.355214 0.145919 0.923326 +vn 0.270205 0.073026 0.960030 +vn 0.315829 -0.009877 0.948765 +vn 0.715138 -0.403394 0.570834 +vn 0.439610 -0.127960 0.889027 +vn 0.411174 -0.175110 0.894580 +vn 0.185412 -0.945621 0.267251 +vn 0.000000 -0.560674 0.828037 +vn 0.000000 -0.950066 0.312049 +vn -0.185412 -0.945621 0.267252 +vn -0.103824 -0.991062 -0.083762 +vn -0.055913 -0.993616 -0.097989 +vn -0.108493 0.230728 0.966951 +vn -0.227538 0.053154 0.972317 +vn -0.297022 0.464072 0.834515 +vn -0.107367 0.612882 0.782846 +vn -0.418322 0.724650 0.547622 +vn -0.135285 0.844558 0.518092 +vn -0.463713 0.849858 0.250423 +vn -0.142162 0.962413 0.231410 +vn -0.141695 0.989910 0.000789 +vn 0.137219 0.962833 0.232646 +vn 0.141972 0.989866 0.003080 +vn 0.463711 0.849858 0.250428 +vn 0.477923 0.878393 -0.003830 +vn 0.797663 0.547759 0.252376 +vn 0.815637 0.576945 -0.043250 +vn 0.988106 0.144731 -0.051951 +vn 0.938143 0.224956 -0.263217 +vn -0.454626 0.282523 0.844687 +vn -0.678646 0.454710 0.576782 +vn -0.797663 0.547759 0.252376 +vn -0.477923 0.878393 -0.003831 +vn -0.132342 0.980470 -0.145479 +vn 0.135234 0.979965 -0.146220 +vn 0.472023 0.860583 -0.191286 +vn 0.778200 0.575732 -0.250872 +vn 0.863954 0.217316 -0.454266 +vn -0.275917 -0.902646 -0.330302 +vn -0.415860 -0.884291 -0.212345 +vn -0.391375 -0.864262 -0.316035 +vn -0.289959 -0.924842 -0.246154 +vn 0.000000 -0.964574 -0.263814 +vn 0.000000 -0.996058 -0.088710 +vn 0.289959 -0.924841 -0.246154 +vn 0.336675 -0.940082 -0.053812 +vn 0.415860 -0.884291 -0.212345 +vn 0.487050 -0.872928 0.027896 +vn 0.451193 -0.888173 -0.087030 +vn 0.492921 -0.861827 0.119515 +vn 0.640604 -0.766170 -0.051084 +vn 0.634958 -0.752318 0.175631 +vn 0.818436 -0.534372 0.211209 +vn 0.585442 -0.740017 0.331110 +vn -0.516124 0.003038 0.856508 +vn -0.819687 0.078932 0.567347 +vn -0.970510 0.098944 0.219818 +vn -0.988106 0.144731 -0.051952 +vn -0.815638 0.576944 -0.043251 +vn -0.934016 0.231580 -0.272001 +vn -0.781975 0.564297 -0.264733 +vn -0.757971 0.530639 -0.379344 +vn -0.498917 0.827391 -0.257886 +vn -0.751480 0.649730 -0.114578 +vn -0.178991 0.966609 -0.183381 +vn -0.359308 0.743693 0.563753 +vn 0.000000 0.721559 0.692353 +vn -0.655266 0.101587 0.748536 +vn -0.684284 0.167393 0.709743 +vn 0.230196 -0.569089 0.789397 +vn -0.605216 0.446777 0.658865 +vn -0.513941 0.333271 0.790440 +vn -0.459704 0.684301 0.566042 +vn -0.305038 0.542687 0.782587 +vn 0.194266 0.765610 0.613272 +vn 0.227556 0.601623 0.765682 +vn 0.520709 0.722807 0.454327 +vn 0.540653 0.581442 0.607963 +vn 0.838991 0.470624 0.273145 +vn 0.832191 0.351341 0.428974 +vn 0.887793 0.002013 0.460239 +vn 0.770521 0.008420 0.637360 +vn 0.561743 -0.418037 0.713926 +vn 0.513773 -0.431573 0.741473 +vn 0.267246 -0.587430 -0.763875 +vn 0.417399 -0.302810 -0.856787 +vn 0.114261 -0.650981 -0.750446 +vn 0.149027 -0.306153 -0.940245 +vn -0.625968 -0.762308 -0.164473 +vn -0.752898 -0.532062 -0.387369 +vn -0.650743 -0.221434 0.726293 +vn -0.662467 -0.224880 0.714540 +vn -0.610137 -0.218613 0.761539 +vn -0.698405 -0.212019 0.683578 +vn -0.603964 -0.406514 0.685546 +vn -0.698754 -0.139913 0.701546 +vn -0.632986 -0.299999 0.713673 +vn -0.406653 0.860707 0.306296 +vn -0.029691 0.592999 0.804656 +vn 0.633183 0.741495 0.221954 +vn 0.143818 0.363847 0.920289 +vn 0.392841 -0.833639 -0.388229 +vn -0.587806 -0.773852 0.235877 +vn -0.570129 -0.618899 0.540294 +vn -0.738391 0.119928 0.663623 +vn -0.825320 0.121391 0.551463 +vn -0.711142 0.084585 0.697942 +vn -0.908308 0.035636 0.416781 +vn -0.847166 -0.158052 0.507276 +vn -0.741241 -0.314158 0.593184 +vn -0.938437 0.074258 0.337375 +vn 0.481867 -0.005280 0.876228 +vn 0.371646 0.724078 0.581025 +vn -0.000000 0.022931 0.999737 +vn 0.386383 -0.177727 0.905053 +vn -0.000000 -0.081839 0.996646 +vn 0.324924 -0.245692 0.913269 +vn 0.000000 -0.043449 0.999056 +vn 0.211351 0.118029 0.970258 +vn -0.000000 0.179632 0.983734 +vn 0.000000 0.220227 0.975449 +vn -0.211351 0.118028 0.970258 +vn -0.282840 0.242462 0.928016 +vn -0.418688 0.101883 0.902397 +vn -0.214832 -0.197629 0.956447 +vn -0.321858 -0.479906 0.816148 +vn -0.475027 -0.291238 0.830380 +vn -0.523516 -0.688565 0.501807 +vn -0.742275 -0.378226 0.553147 +vn -0.883322 -0.435424 0.173631 +vn -0.894383 -0.445642 -0.038505 +vn -0.880311 -0.404778 -0.247399 +vn -0.472023 0.860583 -0.191289 +vn 0.181498 0.965226 -0.188144 +vn 0.497391 0.819806 -0.283762 +vn 0.729643 0.551281 -0.404611 +vn 0.887086 0.435043 -0.154323 +vn 0.606085 -0.641296 0.470532 +vn 0.517508 -0.588904 0.620788 +vn 0.435947 -0.519384 0.734977 +vn 0.542110 -0.662603 0.516792 +vn 0.454210 -0.399028 0.796536 +vn 0.493925 -0.607099 0.622470 +vn 0.499464 -0.361652 0.787238 +vn 0.478616 -0.616326 0.625355 +vn 0.398322 -0.701356 0.591135 +vn 0.424603 -0.587797 0.688627 +vn -0.084974 -0.274360 0.957865 +vn -0.052995 -0.034711 0.997991 +vn 0.128405 0.127766 0.983457 +vn 0.396721 0.200943 0.895675 +vn 0.578998 0.169825 0.797446 +vn 0.854163 -0.519720 -0.017252 +vn 0.993473 -0.113722 0.008819 +vn 0.842992 -0.498154 -0.202997 +vn 0.627673 -0.741330 -0.237607 +vn 0.353775 -0.900813 -0.251754 +vn 0.391375 -0.864262 -0.316035 +vn 0.275917 -0.902646 -0.330302 +vn 0.266007 -0.843569 -0.466510 +vn 0.075104 -0.867682 -0.491414 +vn 0.748568 0.064561 0.659908 +vn 0.812185 0.121577 0.570591 +vn 0.834699 -0.040261 0.549233 +vn 0.824573 -0.070645 0.561327 +vn 0.814414 -0.037911 0.579045 +vn 0.615929 -0.094497 0.782114 +vn 0.593065 -0.094030 0.799645 +vn 0.415598 -0.087941 0.905287 +vn 0.419965 -0.088747 0.903191 +vn -0.336674 -0.940082 -0.053812 +vn 0.000000 -0.994178 0.107750 +vn 0.370623 -0.917629 0.143515 +vn 0.559975 -0.793320 0.238898 +vn 0.494727 -0.812267 0.308979 +vn 0.855432 0.516273 0.041204 +vn 0.593637 0.705269 0.387544 +vn 0.745563 0.658429 -0.102994 +vn 0.912898 0.359760 0.192844 +vn 0.702288 0.300993 0.645132 +vn 0.844453 0.152683 0.513407 +vn 0.709993 -0.092800 0.698067 +vn 0.652692 -0.293672 0.698391 +vn 0.520071 -0.594890 0.612888 +vn 0.736795 0.675808 -0.020419 +vn 0.333634 0.907103 -0.256618 +vn 0.487680 0.491973 -0.721201 +vn 0.116370 0.761084 -0.638129 +vn 0.117867 0.373556 -0.920089 +vn -0.871840 0.218340 -0.438431 +vn 0.122524 0.064870 -0.990343 +vn -0.839685 -0.148748 -0.522306 +vn 0.321858 -0.479905 0.816149 +vn 0.475030 -0.291239 0.830378 +vn 0.523516 -0.688564 0.501807 +vn 0.742276 -0.378225 0.553148 +vn 0.883322 -0.435423 0.173634 +vn 0.970510 0.098944 0.219819 +vn 0.894383 -0.445642 -0.038505 +vn 0.880311 -0.404779 -0.247400 +vn -0.517502 -0.588893 0.620803 +vn -0.606083 -0.641294 0.470538 +vn -0.230139 -0.569071 0.789427 +vn -0.435937 -0.519369 0.734993 +vn 0.053007 -0.034698 0.997991 +vn -0.128410 0.127763 0.983457 +vn 0.305046 0.542684 0.782586 +vn -0.227535 0.601641 0.765674 +vn -0.194221 0.765638 0.613251 +vn -0.520726 0.722785 0.454341 +vn -0.441597 0.362118 0.820891 +vn -0.410192 0.083883 0.908133 +vn -0.419964 -0.088747 0.903191 +vn -0.111154 0.658820 0.744044 +vn -0.417119 0.505013 0.755628 +vn -0.227248 0.485055 0.844440 +vn -0.355215 0.145919 0.923326 +vn -0.318550 0.401296 0.858771 +vn -0.270204 0.073026 0.960030 +vn -0.854163 -0.519720 -0.017252 +vn -0.818436 -0.534372 0.211209 +vn -0.634957 -0.752318 0.175632 +vn -0.585442 -0.740017 0.331110 +vn -0.494727 -0.812267 0.308977 +vn 0.678647 0.454710 0.576782 +vn 0.418312 0.724660 0.547615 +vn 0.297024 0.464074 0.834513 +vn 0.096027 0.617411 0.780758 +vn 0.098576 0.251237 0.962893 +vn -0.986850 -0.152081 0.054751 +vn -0.993473 -0.113722 0.008819 +vn -0.537096 -0.757037 -0.372051 +vn -0.462888 -0.208807 -0.861472 +vn -0.623360 0.179964 0.760943 +vn -0.428118 -0.171957 0.887212 +vn -0.315829 -0.009877 0.948765 +vn 0.398438 -0.792085 -0.462437 +vn 0.452697 -0.804042 -0.385463 +vn 0.595399 -0.636457 -0.490330 +vn 0.558729 -0.742385 -0.369712 +vn 0.722650 -0.500639 -0.476589 +vn -0.454212 -0.399017 0.796541 +vn -0.493912 -0.607078 0.622500 +vn -0.542116 -0.662594 0.516797 +vn -0.499461 -0.361645 0.787244 +vn -0.396721 0.200944 0.895675 +vn -0.579002 0.169821 0.797444 +vn -0.540672 0.581422 0.607965 +vn -0.832184 0.351342 0.428986 +vn -0.838985 0.470622 0.273163 +vn -0.887795 0.002013 0.460235 +vn -0.624106 -0.090829 0.776042 +vn -0.616888 -0.080830 0.782889 +vn -0.415597 -0.087941 0.905288 +vn -0.820400 -0.056374 0.569005 +vn -0.604387 -0.106429 0.789550 +vn -0.832216 -0.044477 0.552666 +vn -0.512614 0.130852 0.848590 +vn -0.748568 0.064561 0.659908 +vn -0.555884 0.220491 0.801484 +vn -0.770405 0.180316 0.611525 +vn 0.953778 -0.066539 0.293054 +vn 0.770561 -0.387873 -0.505758 +vn 0.534600 -0.774839 -0.337383 +vn 0.607478 -0.784926 -0.121913 +vn 0.837020 -0.176303 0.517990 +vn 0.850364 -0.470192 0.236223 +vn 0.943661 -0.150707 0.294603 +vn 0.751558 -0.494850 0.436216 +vn 0.393811 -0.208427 0.895249 +vn 0.348498 -0.541112 0.765341 +vn 0.000000 -0.542662 0.839951 +vn 0.138266 -0.962617 0.232917 +vn -0.000001 -0.961703 0.274094 +vn -0.383239 -0.610955 0.692721 +vn -0.315527 -0.317540 0.894210 +vn -0.389857 -0.123048 0.912618 +vn -0.411455 -0.086606 0.907306 +vn -0.398438 -0.792085 -0.462437 +vn -0.452697 -0.804042 -0.385463 +vn -0.353775 -0.900813 -0.251754 +vn -0.478617 -0.616363 0.625318 +vn -0.513769 -0.431576 0.741474 +vn -0.770516 0.008416 0.637365 +vn -0.324923 -0.245693 0.913269 +vn -0.520071 -0.594891 0.612888 +vn -0.386383 -0.177727 0.905053 +vn -0.652692 -0.293672 0.698391 +vn -0.709994 -0.092800 0.698067 +vn 0.459699 0.684297 0.566051 +vn 0.513936 0.333269 0.790444 +vn 0.084987 -0.274367 0.957862 +vn -0.633183 0.741495 0.221956 +vn -0.736795 0.675808 -0.020418 +vn -0.333634 0.907103 -0.256618 +vn -0.116369 0.761084 -0.638130 +vn 0.978157 0.205051 0.034095 +vn 0.983617 0.122918 0.131869 +vn 0.410188 0.083881 0.908136 +vn -0.266007 -0.843569 -0.466510 +vn -0.075104 -0.867682 -0.491414 +vn -0.000000 -0.936566 -0.350490 +vn -0.761796 0.147760 0.630740 +vn -0.710183 0.443645 0.546644 +vn 0.616578 -0.777111 0.126213 +vn -0.481867 -0.005280 0.876228 +vn -0.693719 0.332354 0.638980 +vn -0.903831 0.414077 0.107837 +vn -0.871837 0.489737 -0.007637 +vn 0.126700 0.845310 0.519036 +vn 0.623360 0.179964 0.760943 +vn -0.251647 -0.902417 0.349740 +vn -0.439611 -0.127959 0.889027 +vn -0.411175 -0.175110 0.894579 +vn -0.000001 -0.434372 0.900734 +vn 0.512614 0.130852 0.848590 +vn 0.282840 0.242462 0.928016 +vn 0.418689 0.101883 0.902396 +vn 0.555884 0.220491 0.801485 +vn 0.770405 0.180316 0.611525 +vn -0.812185 0.121577 0.570591 +vn -0.328785 -0.454331 0.827939 +vn -0.607477 -0.784926 -0.121913 +vn -0.616578 -0.777111 0.126213 +vn 0.594470 -0.100115 0.797861 +vn 0.315527 -0.317540 0.894210 +vn 0.389857 -0.123048 0.912618 +vn 0.234066 -0.895976 -0.377413 +vn -0.424547 0.143869 -0.893902 +vn -0.117867 0.373556 -0.920089 +vn -0.487680 0.491972 -0.721201 +vn 0.424547 0.143869 -0.893902 +vn 0.825320 0.121391 0.551463 +vn 0.819688 0.078929 0.567347 +vn 0.328785 -0.454331 0.827939 +vn 0.428119 -0.171958 0.887212 +vn 0.662467 -0.224880 0.714540 +vn 0.752898 -0.532061 -0.387370 +vn 0.605163 0.446785 0.658909 +vn 0.655254 0.101590 0.748546 +vn -0.602492 -0.292067 0.742766 +vn -0.686211 -0.056117 0.725234 +vn -0.712714 0.686765 -0.142804 +vn -0.844453 0.152683 0.513407 +vn -0.398312 -0.701367 0.591127 +vn -0.561746 -0.418043 0.713920 +vn 0.383238 -0.610954 0.692722 +vn 0.522792 -0.452974 -0.722152 +vn 0.716550 -0.384527 -0.581975 +vn 0.462888 -0.208807 -0.861472 +vn -0.247009 -0.529037 0.811854 +vn 0.000000 -0.554485 0.832193 +vn -0.426160 -0.433699 0.793910 +vn -0.850364 -0.470192 0.236223 +vn -0.837021 -0.176304 0.517990 +vn -0.943662 -0.150707 0.294602 +vn -0.751558 -0.494850 0.436216 +vn -0.338553 -0.940526 0.028145 +vn -0.291621 -0.951457 0.098422 +vn -0.393811 -0.208428 0.895249 +vn -0.352962 -0.530414 0.770765 +vn -0.143054 -0.962595 0.230099 +vn 0.338553 -0.940526 0.028145 +vn 0.291621 -0.951457 0.098419 +vn 0.454625 0.282523 0.844687 +vn 0.603964 -0.406513 0.685546 +vn 0.738391 0.119927 0.663624 +vn -0.984682 0.121176 0.125373 +vn 0.066278 0.677228 0.732782 +vn 0.411455 -0.086606 0.907306 +vn -0.978157 0.205051 0.034095 +vn 0.055913 -0.993616 -0.097988 +vn 0.260188 -0.133234 -0.956322 +vn -0.023279 0.998505 0.049451 +vn 0.103824 -0.991062 -0.083762 +vn 0.999959 0.008797 -0.002076 +vn 0.999952 0.009241 -0.003355 +vn 0.000000 -0.989102 -0.147233 +vn 0.247009 -0.529037 0.811854 +vn -0.593636 0.705269 0.387547 +vn -0.066278 0.677228 0.732782 +vn -0.260187 -0.133233 -0.956322 +vn -0.999959 0.008797 -0.002076 +vn -0.999952 0.009241 -0.003355 +vn 0.000000 -0.210417 0.977612 +vn 0.426160 -0.433699 0.793910 +vn 0.251647 -0.902416 0.349741 +vn 0.684298 0.167398 0.709728 +vn -0.424623 -0.587792 0.688619 +vn 0.000000 0.177647 0.984094 +vn 0.000000 0.940995 0.338419 +vn -0.057404 0.966906 0.248590 +vn 0.057404 0.966906 0.248590 +vn 0.221137 0.150809 0.963512 +vn -0.000205 0.983959 0.178392 +vn 0.186947 -0.951805 0.243144 +vn 0.334117 -0.447972 0.829269 +vn 0.053518 0.941920 0.331547 +vn -0.000000 0.092735 -0.995691 +vn 0.023279 0.998505 0.049450 +vn -0.334117 -0.447972 0.829269 +vn -0.186948 -0.951805 0.243143 +vn 0.000205 0.983960 0.178392 +vn -0.053518 0.941920 0.331545 +vn -0.221137 0.150809 0.963512 +vn -0.496995 -0.507260 0.704048 +vn -0.491110 -0.049665 0.869681 +vn 0.496996 -0.507261 0.704047 +vn 0.292163 -0.514783 0.806002 +vn 0.491109 -0.049667 0.869681 +vn 0.000000 -0.545284 0.838252 +vn -0.292163 -0.514783 0.806002 +vn -0.691117 -0.085432 0.717676 +vn -0.831546 -0.426379 0.355995 +vn -0.698017 -0.526599 0.485249 +vn -0.829716 0.047170 0.556189 +vn -0.506985 0.413376 0.756364 +vn -0.864626 0.271128 0.422980 +vn -0.784702 0.507524 0.355895 +vn -0.954811 0.294860 -0.037339 +vn -0.872517 0.481335 -0.083845 +vn -0.752062 0.656045 -0.063302 +vn -0.615138 0.696075 0.370250 +vn -0.403611 0.792477 0.457251 +vn -0.205609 0.780054 0.590966 +vn -0.080047 0.970144 0.228941 +vn 0.088504 0.939645 0.330505 +vn -0.014554 0.459642 0.887985 +vn -0.083239 0.223690 0.971099 +vn 0.420516 0.193033 0.886513 +vn -0.063610 0.663657 0.745327 +vn 0.220166 0.858580 0.462998 +vn 0.368838 -0.008926 0.929451 +vn 0.230882 -0.182986 0.955620 +vn -0.250833 0.016855 0.967884 +vn 0.077924 -0.358608 0.930230 +vn -0.128819 -0.470313 0.873047 +vn 0.344763 0.743024 0.573632 +vn 0.408025 0.583863 0.701869 +vn 0.457203 0.393393 0.797626 +vn -0.480607 -0.099695 0.871250 +vn -0.531192 -0.555236 0.639959 +vn -0.599377 0.799365 -0.041987 +vn -0.431029 0.901528 0.038221 +vn -0.249531 0.961888 0.111830 +vn -0.996546 0.081511 0.015848 +vn -0.985975 -0.118213 0.117809 +vn -0.926215 -0.312348 0.211103 +vn -0.329422 -0.557098 0.762314 +vn 0.519305 -0.398701 0.755884 +vn 0.328168 -0.652463 0.683079 +vn 0.179491 -0.464843 0.867008 +vn 0.564445 -0.567339 0.599607 +vn 0.846601 -0.272174 0.457371 +vn 0.844268 -0.366108 0.391377 +vn 0.975691 -0.195814 0.098410 +vn 0.963809 -0.250860 0.090226 +vn 0.089527 -0.768085 0.634059 +vn 0.128533 -0.894100 0.429028 +vn 0.233719 -0.959021 0.160169 +vn 0.236386 -0.833064 0.500125 +vn 0.305208 -0.589144 0.748170 +vn 0.566223 -0.424988 0.706241 +vn -0.217672 -0.931017 0.292961 +vn 0.100760 -0.994841 0.011787 +vn 0.460614 -0.385718 -0.799410 +vn 0.510244 -0.241635 -0.825387 +vn 0.848380 -0.158019 -0.505253 +vn 0.131788 -0.401645 -0.906264 +vn 0.387334 -0.601910 0.698338 +vn 0.081997 -0.713065 0.696286 +vn 0.608161 -0.424882 0.670533 +vn 0.872277 -0.158837 0.462497 +vn 0.900809 -0.166099 0.401190 +vn 0.985292 -0.151172 0.079665 +vn 0.982224 -0.166533 0.086624 +vn 0.965721 -0.148695 -0.212773 +vn 0.972463 -0.110922 -0.204967 +vn 0.848617 -0.173777 -0.499651 +vn 0.759376 -0.545732 -0.354294 +vn 0.400849 -0.585523 -0.704616 +vn 0.475787 -0.651953 -0.590410 +vn 0.019433 -0.866850 -0.498191 +vn -0.092606 -0.704147 -0.703990 +vn -0.059957 -0.977914 -0.200223 +vn -0.822935 -0.497426 -0.274490 +vn 0.000000 -0.992137 -0.125160 +vn 0.138235 -0.207053 -0.968514 +vn 0.153557 -0.056811 -0.986505 +vn 0.519397 -0.085108 -0.850284 +vn 0.000000 -0.248808 -0.968553 +vn -0.000000 -0.451474 -0.892284 +vn 0.093265 -0.660985 -0.744581 +vn -0.000000 -0.820058 -0.572280 +vn 0.000000 -0.957638 -0.287976 +vn 0.123046 -0.942151 0.311788 +vn 0.042113 -0.776334 0.628914 +vn 0.000000 -0.998636 -0.052219 +vn -0.660838 -0.745720 0.084817 +vn 0.000000 -0.999157 0.041053 +vn 0.000000 -0.993584 0.113099 +vn -0.000000 -0.879973 0.475023 +vn 0.952653 -0.206481 -0.223199 +vn -0.972463 -0.110922 -0.204966 +vn -0.848380 -0.158020 -0.505253 +vn -0.848617 -0.173777 -0.499651 +vn -0.965721 -0.148695 -0.212772 +vn -0.982224 -0.166533 0.086624 +vn -0.985292 -0.151172 0.079665 +vn -0.153557 -0.056811 -0.986505 +vn -0.138235 -0.207053 -0.968514 +vn -0.519397 -0.085108 -0.850284 +vn 0.000000 -0.125951 -0.992037 +vn -0.100760 -0.994841 0.011787 +vn 0.660838 -0.745720 0.084817 +vn -0.123046 -0.942151 0.311788 +vn -0.042113 -0.776334 0.628914 +vn -0.000000 -0.790024 0.613077 +vn 0.822935 -0.497426 -0.274490 +vn -0.131788 -0.401645 -0.906263 +vn -0.857601 -0.250368 -0.449262 +vn 0.857601 -0.250368 -0.449262 +vn -0.936688 -0.050290 -0.346534 +vn -0.353512 -0.456433 -0.816516 +vn -0.400836 -0.173636 -0.899545 +vn -0.981787 -0.081920 0.171418 +vn -0.826954 -0.328157 0.456575 +vn -0.762894 -0.209059 0.611791 +vn 0.571902 -0.369104 -0.732591 +vn 0.934433 -0.233422 -0.268979 +vn -0.249382 -0.652885 0.715227 +vn -0.310152 -0.332971 0.890469 +vn 0.407446 -0.029921 -0.912739 +vn -0.464758 0.018066 -0.885254 +vn 0.466068 -0.061519 -0.882608 +vn 0.934185 -0.085035 -0.346507 +vn 0.942301 -0.127656 -0.309472 +vn 0.996257 -0.020845 0.083890 +vn 0.984662 -0.147897 0.092562 +vn 0.833690 -0.058436 0.549133 +vn 0.836798 -0.199880 0.509722 +vn 0.493619 -0.059685 0.867628 +vn 0.506602 -0.222876 0.832875 +vn 0.052999 -0.044203 0.997616 +vn 0.118903 -0.253915 0.959890 +vn -0.414876 -0.089808 0.905435 +vn -0.931211 -0.052094 -0.360740 +vn -0.979165 -0.093624 0.180197 +vn -0.784060 -0.116070 0.609736 +vn 0.436669 0.029845 -0.899127 +vn 0.597078 0.315325 -0.737609 +vn -0.040106 0.315479 -0.948085 +vn 0.914794 0.234064 -0.329190 +vn 0.917944 0.019302 -0.396240 +vn 0.981354 0.179032 0.069948 +vn 0.989225 -0.014886 0.145644 +vn 0.842804 0.155501 0.515268 +vn 0.783678 -0.000667 0.621166 +vn 0.531248 0.000952 0.847216 +vn 0.508992 -0.026834 0.860353 +vn 0.081776 -0.047037 0.995540 +vn 0.779888 -0.020467 0.625585 +vn 0.988501 0.078826 0.129042 +vn 0.918472 0.139750 -0.369973 +vn 0.399240 -0.082061 -0.913167 +vn -0.977146 -0.078472 0.197556 +vn -0.945849 0.131087 -0.296961 +vn -0.985429 0.091389 0.143448 +vn -0.938438 0.008498 -0.345343 +vn -0.977826 0.063109 0.199685 +vn -0.935354 -0.022567 -0.352994 +vn -0.978798 0.027793 0.202936 +vn -0.932990 -0.013206 -0.359659 +vn -0.589272 0.220135 -0.777367 +vn -0.445647 0.031684 -0.894648 +vn -0.438984 -0.104847 -0.892357 +vn -0.442497 0.240746 -0.863850 +vn 0.426924 0.281951 -0.859209 +vn 0.587002 0.162900 0.793028 +vn 0.075717 0.001763 0.997128 +vn -0.430220 -0.087519 0.898472 +vn 0.049835 0.126483 0.990716 +vn -0.451341 -0.016017 0.892208 +vn -0.757876 -0.110873 0.642909 +vn 0.977536 0.202991 0.056733 +vn 0.902737 0.178628 -0.391354 +vn -0.779873 -0.018796 0.625656 +vn -0.493468 0.095963 0.864454 +vn -0.830925 0.080676 0.550505 +vn -0.000000 0.103240 0.994657 +vn -0.179757 0.108777 0.977678 +vn -0.274352 0.102266 0.956176 +vn 0.000000 0.077125 0.997021 +vn 0.179756 0.108777 0.977678 +vn -0.000000 0.312039 0.950069 +vn 0.155248 0.277413 0.948124 +vn -0.000000 0.488517 0.872554 +vn 0.081670 0.448419 0.890084 +vn -0.408645 -0.172700 -0.896205 +vn -0.168846 -0.072633 -0.982963 +vn -0.465471 0.011489 -0.884988 +vn -0.202528 -0.139040 -0.969356 +vn -0.186722 -0.021006 -0.982188 +vn 0.000000 -0.175043 -0.984561 +vn 0.000000 0.007549 -0.999972 +vn 0.186722 -0.021006 -0.982188 +vn 0.168846 -0.072633 -0.982963 +vn 0.408645 -0.172700 -0.896205 +vn 0.465471 0.011489 -0.884989 +vn 0.202528 -0.139040 -0.969356 +vn 0.000000 -0.107341 -0.994222 +vn -0.194866 -0.089254 0.976761 +vn -0.155248 0.277413 0.948124 +vn -0.189653 0.447892 0.873742 +vn -0.054167 0.069909 0.996082 +vn 0.194866 -0.089254 0.976761 +vn -0.867212 0.193569 0.458774 +vn -0.878874 -0.034938 0.475774 +vn -0.923539 0.206401 0.323226 +vn -0.650772 0.110697 0.751160 +vn 0.878874 -0.034939 0.475773 +vn 0.867212 0.193569 0.458774 +vn 0.923539 0.206401 0.323226 +vn 0.650772 0.110697 0.751160 +vn 0.274352 0.102266 0.956176 +vn -0.081670 0.448419 0.890085 +vn 0.189653 0.447892 0.873742 +vn 0.054168 0.069911 0.996081 +vn 0.062990 0.993953 0.089939 +vn -0.931024 0.331769 0.152065 +vn -0.822130 0.543410 0.169727 +vn 0.064239 0.978788 -0.194543 +vn 0.312408 0.925255 -0.215185 +vn 0.046912 0.817893 -0.573456 +vn 0.273479 0.733076 -0.622743 +vn 0.035608 0.531910 -0.846052 +vn 0.269769 0.430898 -0.861134 +vn 0.130820 0.206225 -0.969720 +vn 0.357933 0.083252 -0.930029 +vn -0.967900 0.225693 0.110600 +vn -0.904910 0.421344 0.060058 +vn -0.929804 0.341420 0.137463 +vn -0.858894 0.504294 0.089377 +vn -0.000000 0.233114 -0.972449 +vn -0.000000 0.999536 -0.030460 +vn 0.858895 0.504294 0.089377 +vn 0.277250 0.798589 0.534217 +vn -0.591502 0.743773 0.311331 +vn -0.950608 0.250128 0.183797 +vn 0.209504 0.925624 0.315164 +vn 0.419433 0.806050 0.417564 +vn 0.350862 0.928637 0.120538 +vn 0.954750 0.285647 -0.082810 +vn 0.959680 0.232513 -0.157964 +vn 0.941135 0.185735 -0.282432 +vn -0.516268 0.628830 0.581412 +vn -0.957767 0.287517 0.003986 +vn -0.977693 0.207232 0.034234 +vn -0.419433 0.806050 0.417564 +vn -0.317789 0.694770 0.645217 +vn -0.277250 0.798589 0.534217 +vn 0.956063 0.199914 0.214422 +vn 0.992017 0.067871 0.106280 +vn -0.954750 0.285648 -0.082810 +vn -0.350862 0.928637 0.120539 +vn -0.209504 0.925624 0.315164 +vn -0.062990 0.993953 0.089939 +vn 0.822131 0.543409 0.169728 +vn 0.931024 0.331770 0.152065 +vn -0.959680 0.232512 -0.157965 +vn -0.312408 0.925255 -0.215185 +vn -0.064239 0.978788 -0.194543 +vn 0.904910 0.421344 0.060059 +vn -0.941135 0.185735 -0.282432 +vn -0.273479 0.733076 -0.622743 +vn -0.046911 0.817892 -0.573456 +vn -0.035608 0.531909 -0.846052 +vn 0.929805 0.341420 0.137461 +vn 0.317789 0.694770 0.645217 +vn -0.988625 0.057615 0.138932 +vn -0.963771 0.164594 0.209894 +vn -0.956064 0.199914 0.214422 +vn -0.992017 0.067871 0.106280 +vn -0.910359 0.213002 -0.354792 +vn -0.269768 0.430898 -0.861134 +vn -0.130820 0.206225 -0.969720 +vn 0.591502 0.743773 0.311331 +vn 0.967900 0.225693 0.110600 +vn 0.988625 0.057614 0.138932 +vn 0.963770 0.164594 0.209894 +vn 0.516268 0.628831 0.581412 +vn 0.910359 0.213001 -0.354792 +vn 0.957767 0.287517 0.003986 +vn 0.929468 0.261599 -0.260105 +vn 0.950607 0.250128 0.183797 +vn -0.357933 0.083252 -0.930029 +vn -0.929469 0.261599 -0.260104 +vn 0.977693 0.207232 0.034234 +vn 0.331230 0.512594 0.792171 +vn -0.910753 0.318422 0.262938 +vn -0.312419 0.626159 0.714366 +vn 0.277088 0.581207 0.765128 +vn -0.635057 0.491354 0.596049 +vn -0.932875 0.344334 0.105729 +vn -0.277088 0.581207 0.765128 +vn 0.462173 0.645503 0.608047 +vn 0.541411 0.041110 -0.839752 +vn 0.342421 0.926728 0.154671 +vn 0.852876 0.248211 -0.459340 +vn 0.554855 0.467392 0.688244 +vn 0.635057 0.491354 0.596049 +vn 0.932875 0.344334 0.105728 +vn -0.331230 0.512594 0.792171 +vn -0.554855 0.467392 0.688244 +vn -0.541411 0.041111 -0.839752 +vn -0.779036 -0.208127 -0.591427 +vn -0.852876 0.248212 -0.459340 +vn 0.779036 -0.208127 -0.591427 +vn -0.462173 0.645504 0.608047 +vn -0.342421 0.926728 0.154671 +vn 0.910753 0.318422 0.262938 +vn 0.312419 0.626159 0.714366 +vn -0.236386 -0.833064 0.500126 +vn -0.089527 -0.768085 0.634059 +vn -0.128533 -0.894100 0.429027 +vn -0.328168 -0.652463 0.683079 +vn -0.305208 -0.589144 0.748170 +vn -0.566223 -0.424987 0.706241 +vn -0.608161 -0.424883 0.670533 +vn -0.460614 -0.385718 -0.799410 +vn -0.093265 -0.660985 -0.744581 +vn -0.510243 -0.241635 -0.825387 +vn -0.519305 -0.398702 0.755883 +vn -0.179491 -0.464844 0.867008 +vn -0.564446 -0.567338 0.599607 +vn -0.844268 -0.366108 0.391377 +vn -0.233719 -0.959021 0.160169 +vn 0.217673 -0.931017 0.292962 +vn -0.081996 -0.713065 0.696286 +vn -0.387334 -0.601911 0.698338 +vn -0.846601 -0.272175 0.457371 +vn -0.975691 -0.195814 0.098410 +vn -0.963809 -0.250860 0.090226 +vn -0.019433 -0.866849 -0.498191 +vn -0.872277 -0.158837 0.462497 +vn -0.900809 -0.166098 0.401191 +vn -0.952653 -0.206481 -0.223199 +vn -0.759376 -0.545732 -0.354293 +vn -0.475787 -0.651953 -0.590410 +vn -0.400849 -0.585522 -0.704616 +vn 0.092606 -0.704147 -0.703990 +vn 0.059957 -0.977914 -0.200223 +vn 0.855676 -0.349396 0.381761 +vn 0.885250 -0.190893 0.424138 +vn 0.584639 -0.513470 0.628128 +vn 0.984001 -0.119105 0.132498 +vn 0.953613 -0.284583 0.098156 +vn 0.980075 -0.078892 -0.182291 +vn 0.953262 -0.245132 -0.176642 +vn 0.835743 0.008211 -0.549059 +vn 0.853241 -0.119161 -0.507721 +vn -0.325905 -0.271575 0.905557 +vn -0.000000 -0.471014 0.882126 +vn 0.000000 -0.265564 0.964093 +vn -0.286578 -0.455573 0.842808 +vn -0.624473 -0.168282 0.762702 +vn -0.600503 -0.327721 0.729380 +vn -0.900333 -0.046540 0.432706 +vn -0.885250 -0.190893 0.424138 +vn 0.988656 0.044300 0.143516 +vn 0.982313 0.065242 -0.175515 +vn 0.900333 -0.046540 0.432706 +vn 0.600503 -0.327721 0.729380 +vn 0.325904 -0.271575 0.905557 +vn 0.286578 -0.455573 0.842809 +vn 0.161983 -0.649288 0.743093 +vn 0.346539 -0.579869 0.737335 +vn 0.624473 -0.168282 0.762702 +vn -0.980075 -0.078892 -0.182290 +vn -0.988656 0.044300 0.143516 +vn -0.982313 0.065242 -0.175515 +vn -0.984001 -0.119105 0.132498 +vn -0.953613 -0.284583 0.098157 +vn -0.855676 -0.349396 0.381761 +vn -0.584639 -0.513470 0.628128 +vn -0.346539 -0.579869 0.737335 +vn -0.953262 -0.245132 -0.176642 +vn -0.835743 0.008212 -0.549059 +vn -0.853241 -0.119161 -0.507721 +vn -0.161983 -0.649288 0.743093 +vn -0.000000 -0.706295 0.707917 +vn -0.482665 0.130710 -0.865996 +vn -0.503008 0.077474 -0.860802 +vn -0.161256 0.150980 -0.975296 +vn -0.157857 0.104214 -0.981947 +vn -0.000000 0.082651 -0.996579 +vn 0.157857 0.104214 -0.981947 +vn 0.482664 0.130710 -0.865997 +vn 0.503008 0.077474 -0.860803 +vn 0.161256 0.150980 -0.975296 +vn 0.000000 0.123518 -0.992342 +vn 0.826954 -0.328157 0.456575 +vn 0.249382 -0.652885 0.715227 +vn 0.353513 -0.456433 -0.816516 +vn 0.936688 -0.050290 -0.346534 +vn 0.400836 -0.173636 -0.899545 +vn -0.571902 -0.369105 -0.732591 +vn 0.981787 -0.081920 0.171418 +vn -0.836798 -0.199880 0.509722 +vn -0.984662 -0.147897 0.092562 +vn -0.506602 -0.222877 0.832875 +vn -0.118904 -0.253916 0.959890 +vn 0.310152 -0.332971 0.890469 +vn 0.414876 -0.089808 0.905435 +vn -0.053000 -0.044203 0.997616 +vn 0.784060 -0.116071 0.609736 +vn 0.762894 -0.209059 0.611791 +vn 0.979165 -0.093624 0.180197 +vn -0.934433 -0.233422 -0.268979 +vn -0.942301 -0.127656 -0.309472 +vn -0.466068 -0.061519 -0.882608 +vn -0.934185 -0.085035 -0.346508 +vn -0.407447 -0.029920 -0.912739 +vn 0.464758 0.018066 -0.885254 +vn 0.931211 -0.052094 -0.360740 +vn 0.442497 0.240746 -0.863850 +vn 0.932990 -0.013204 -0.359659 +vn 0.978798 0.027793 0.202936 +vn -0.996257 -0.020845 0.083889 +vn -0.902737 0.178629 -0.391353 +vn -0.977536 0.202991 0.056733 +vn -0.426924 0.281950 -0.859209 +vn 0.938438 0.008497 -0.345342 +vn 0.977826 0.063108 0.199685 +vn 0.977146 -0.078472 0.197557 +vn 0.935354 -0.022565 -0.352993 +vn 0.445648 0.031684 -0.894648 +vn 0.438983 -0.104846 -0.892357 +vn -0.436669 0.029845 -0.899127 +vn -0.399241 -0.082062 -0.913166 +vn -0.917944 0.019302 -0.396241 +vn -0.918472 0.139749 -0.369973 +vn -0.989225 -0.014886 0.145643 +vn -0.988501 0.078826 0.129042 +vn -0.493619 -0.059685 0.867628 +vn -0.833690 -0.058436 0.549132 +vn 0.945849 0.131087 -0.296961 +vn 0.985429 0.091389 0.143448 +vn 0.589272 0.220135 -0.777367 +vn 0.040106 0.315479 -0.948085 +vn -0.597079 0.315325 -0.737609 +vn -0.914794 0.234065 -0.329190 +vn -0.779888 -0.020467 0.625584 +vn -0.783678 -0.000667 0.621166 +vn -0.842804 0.155501 0.515268 +vn -0.981354 0.179033 0.069947 +vn -0.508992 -0.026834 0.860353 +vn -0.531248 0.000952 0.847216 +vn -0.587002 0.162900 0.793027 +vn -0.081776 -0.047037 0.995540 +vn -0.075717 0.001763 0.997128 +vn -0.049835 0.126483 0.990716 +vn 0.430220 -0.087519 0.898472 +vn 0.451341 -0.016017 0.892208 +vn 0.493468 0.095963 0.864454 +vn 0.757876 -0.110873 0.642909 +vn 0.779873 -0.018796 0.625656 +vn 0.830925 0.080676 0.550505 +vn -0.442859 -0.737473 0.509912 +vn -0.984204 0.144845 0.101801 +vn -0.580612 -0.783145 0.222652 +vn -0.851490 0.279931 0.443399 +vn -0.199279 -0.682815 0.702888 +vn -0.497957 0.431211 0.752393 +vn 0.039660 -0.650726 0.758276 +vn 0.014591 0.471154 0.881930 +vn 0.295741 -0.651875 0.698281 +vn 0.580753 0.441166 0.684178 +vn 0.481477 -0.702509 0.524081 +vn 0.852109 0.313896 0.418783 +vn 0.613357 -0.754469 0.233601 +vn 0.967585 0.249557 0.038746 +vn 0.543322 -0.835410 -0.083011 +vn 0.929021 0.197736 -0.312762 +vn 0.641061 0.202725 -0.740232 +vn -0.025449 0.248549 -0.968285 +vn -0.616680 0.217094 -0.756688 +vn -0.929022 0.197734 -0.312762 +vn -0.641061 0.202725 -0.740232 +vn 0.025449 0.248549 -0.968285 +vn -0.005410 -0.887041 -0.461660 +vn 0.290915 -0.886306 -0.360320 +vn 0.951217 0.118082 -0.285030 +vn 0.535448 -0.841986 -0.065994 +vn 0.616680 0.217094 -0.756688 +vn 0.984204 0.144845 0.101801 +vn 0.442860 -0.737473 0.509911 +vn 0.580612 -0.783145 0.222651 +vn 0.851490 0.279931 0.443399 +vn 0.199279 -0.682814 0.702889 +vn 0.497957 0.431211 0.752393 +vn -0.039660 -0.650726 0.758276 +vn -0.014591 0.471154 0.881930 +vn -0.295741 -0.651874 0.698282 +vn -0.580753 0.441166 0.684178 +vn -0.481477 -0.702509 0.524081 +vn -0.852109 0.313896 0.418783 +vn -0.613358 -0.754469 0.233601 +vn -0.967585 0.249556 0.038745 +vn -0.543322 -0.835410 -0.083011 +vn -0.290914 -0.886306 -0.360320 +vn -0.951217 0.118082 -0.285030 +vn -0.535447 -0.841987 -0.065994 +vn -0.011350 -0.982370 0.186604 +vn -0.320393 -0.872985 -0.367759 +vn 0.011350 -0.982370 0.186604 +vn 0.320393 -0.872985 -0.367758 +vn 0.005411 -0.887041 -0.461659 +vn -0.000000 -0.041853 0.999124 +vn 0.306192 -0.045031 0.950904 +vn 0.632378 0.020539 0.774388 +vn 0.883149 0.120962 0.453228 +vn 0.943155 0.227586 0.242206 +vn 0.971436 0.204395 0.120559 +vn 0.994552 -0.062758 0.083237 +vn 0.974377 -0.093829 -0.204413 +vn 0.908905 0.374828 -0.182744 +vn -0.440231 -0.223350 0.869662 +vn -0.306192 -0.045031 0.950904 +vn -0.403173 0.295015 0.866267 +vn -0.520793 0.067517 0.851009 +vn -0.649631 0.180735 0.738454 +vn -0.587648 0.402007 0.702183 +vn -0.914762 0.237436 0.326856 +vn -0.810773 0.108924 -0.575136 +vn -0.824561 0.116960 -0.553551 +vn -0.959850 0.207022 -0.189285 +vn -0.971436 0.204395 0.120559 +vn -0.974377 -0.093829 -0.204413 +vn -0.994552 -0.062758 0.083237 +vn -0.908905 0.374829 -0.182744 +vn -0.919761 0.391848 -0.022267 +vn -0.632378 0.020539 0.774388 +vn -0.883149 0.120962 0.453228 +vn -0.943155 0.227586 0.242206 +vn -0.962917 -0.083663 0.256499 +vn 0.810774 0.108925 -0.575136 +vn 0.824561 0.116960 -0.553551 +vn 0.959850 0.207022 -0.189285 +vn 0.914762 0.237436 0.326855 +vn 0.587648 0.402007 0.702183 +vn 0.405068 0.448830 0.796537 +vn 0.919761 0.391848 -0.022268 +vn 0.962917 -0.083663 0.256499 +vn 0.935305 0.335470 0.112538 +vn 0.898053 0.049769 0.437063 +vn 0.852215 0.219654 0.474848 +vn -0.405068 0.448830 0.796537 +vn 0.649631 0.180735 0.738454 +vn 0.403173 0.295015 0.866267 +vn 0.520793 0.067517 0.851009 +vn 0.093263 0.606078 0.789919 +vn 0.000000 0.997878 0.065114 +vn -0.000000 0.561730 0.827320 +vn -0.129986 0.990944 0.033671 +vn 0.198591 0.970923 -0.133677 +vn 0.263764 0.964571 -0.005575 +vn -0.935305 0.335469 0.112538 +vn -0.898053 0.049769 0.437063 +vn 0.440230 -0.223349 0.869662 +vn -0.852215 0.219654 0.474848 +vn -0.263764 0.964571 -0.005575 +vn -0.220114 0.948168 -0.229189 +vn -0.198591 0.970923 -0.133677 +vn -0.093264 0.606078 0.789919 +vn 0.497823 0.814462 -0.298033 +vn 0.220113 0.948168 -0.229189 +vn 0.129986 0.990944 0.033671 +vn -0.497823 0.814462 -0.298033 +vn -0.462448 0.119047 -0.878618 +vn -0.153482 0.053052 -0.986726 +vn 0.000000 0.039540 -0.999218 +vn 0.153482 0.053052 -0.986726 +vn 0.462447 0.119047 -0.878619 +vn 0.083240 0.223691 0.971099 +vn -0.420516 0.193033 0.886513 +vn -0.368837 -0.008926 0.929451 +vn 0.014554 0.459642 0.887985 +vn 0.506985 0.413376 0.756364 +vn 0.063610 0.663657 0.745327 +vn 0.205608 0.780054 0.590966 +vn -0.220166 0.858580 0.462999 +vn -0.088506 0.939646 0.330504 +vn 0.080047 0.970143 0.228943 +vn 0.403610 0.792477 0.457252 +vn 0.615139 0.696074 0.370250 +vn 0.784702 0.507524 0.355896 +vn 0.752062 0.656045 -0.063302 +vn 0.872517 0.481335 -0.083845 +vn 0.954811 0.294859 -0.037340 +vn 0.864626 0.271128 0.422980 +vn 0.829716 0.047170 0.556189 +vn 0.691117 -0.085432 0.717676 +vn 0.831546 -0.426380 0.355995 +vn 0.249529 0.961888 0.111832 +vn 0.431033 0.901526 0.038223 +vn 0.599384 0.799360 -0.041989 +vn 0.996547 0.081511 0.015848 +vn 0.985975 -0.118213 0.117809 +vn 0.926215 -0.312348 0.211103 +vn -0.230881 -0.182985 0.955620 +vn 0.250834 0.016856 0.967884 +vn -0.077923 -0.358608 0.930230 +vn 0.128819 -0.470313 0.873047 +vn 0.480608 -0.099695 0.871250 +vn 0.329422 -0.557098 0.762314 +vn 0.531192 -0.555236 0.639959 +vn 0.698017 -0.526599 0.485249 +vn -0.344764 0.743023 0.573632 +vn -0.408025 0.583863 0.701869 +vn -0.457202 0.393392 0.797627 +vn 0.296844 -0.229920 0.926834 +vn 0.213770 -0.360234 0.908039 +vn 0.400555 -0.264575 0.877243 +vn 0.117639 -0.257131 0.959190 +vn 0.092099 -0.138782 0.986031 +vn -0.115858 -0.125696 0.985280 +vn 0.081011 -0.080648 0.993445 +vn -0.140232 -0.081331 0.986773 +vn -0.109826 -0.022340 0.993700 +vn 0.328860 -0.133751 0.934859 +vn 0.350061 -0.061974 0.934675 +vn 0.526824 -0.050498 0.848473 +vn 0.355516 0.027398 0.934268 +vn 0.492909 0.006865 0.870054 +vn 0.451154 0.052293 0.890913 +vn 0.607171 -0.010157 0.794506 +vn 0.523095 -0.099129 0.846490 +vn 0.671887 -0.107714 0.732780 +vn 0.666682 -0.107825 0.737502 +vn 0.497104 -0.162877 0.852267 +vn 0.630470 -0.193523 0.751702 +vn 0.663369 -0.068588 0.745143 +vn 0.132969 0.012154 0.991046 +vn 0.222588 0.092860 0.970480 +vn -0.073612 -0.192180 0.978595 +vn -0.009106 -0.424699 0.905289 +vn 0.085236 -0.444463 0.891733 +vn 0.347966 0.093672 0.932816 +vn -0.296844 -0.229920 0.926834 +vn -0.400555 -0.264574 0.877244 +vn -0.213770 -0.360234 0.908039 +vn -0.117639 -0.257131 0.959190 +vn -0.092099 -0.138782 0.986031 +vn 0.115859 -0.125696 0.985280 +vn -0.081011 -0.080648 0.993445 +vn 0.140232 -0.081331 0.986773 +vn 0.109826 -0.022340 0.993700 +vn -0.328860 -0.133751 0.934859 +vn -0.350061 -0.061974 0.934675 +vn -0.526823 -0.050498 0.848473 +vn -0.355516 0.027398 0.934269 +vn -0.492908 0.006865 0.870054 +vn -0.451153 0.052293 0.890913 +vn -0.607171 -0.010157 0.794507 +vn -0.523095 -0.099129 0.846490 +vn -0.666682 -0.107825 0.737502 +vn -0.671887 -0.107714 0.732780 +vn -0.497104 -0.162877 0.852267 +vn -0.630470 -0.193522 0.751703 +vn -0.663368 -0.068588 0.745143 +vn -0.132969 0.012154 0.991046 +vn -0.222588 0.092860 0.970480 +vn 0.073613 -0.192181 0.978595 +vn 0.009107 -0.424698 0.905289 +vn -0.085236 -0.444463 0.891733 +vn -0.347965 0.093672 0.932816 +s 1 +g polySurface15 +usemtl lambert2SG +f 3/1/1 2/2/2 1/3/3 +f 4/4/4 2/2/2 3/1/1 +f 5/5/5 4/4/4 3/1/1 +f 6/6/6 4/4/4 5/5/5 +f 7/7/7 6/6/6 5/5/5 +f 8/8/8 6/6/6 7/7/7 +f 9/9/9 8/8/8 7/7/7 +f 10/10/10 8/8/8 9/9/9 +f 11/11/11 10/10/10 9/9/9 +f 12/12/12 10/10/10 11/11/11 +f 13/13/13 12/12/12 11/11/11 +f 14/14/14 12/12/12 13/13/13 +f 15/15/15 14/14/14 13/13/13 +f 16/16/16 14/14/14 15/15/15 +f 17/17/17 16/16/16 15/15/15 +f 18/18/18 16/16/16 17/17/17 +f 19/19/19 18/18/18 17/17/17 +f 20/20/20 18/18/18 19/19/19 +f 21/21/21 20/20/20 19/19/19 +f 22/22/22 20/20/20 21/21/21 +f 23/23/23 22/22/22 21/21/21 +f 24/24/24 22/22/22 23/23/23 +f 25/25/25 24/24/24 23/23/23 +f 26/26/26 24/24/24 25/25/25 +f 27/27/27 26/26/26 25/25/25 +f 28/28/28 26/26/26 27/27/27 +f 29/29/29 28/28/28 27/27/27 +f 30/30/30 28/28/28 29/29/29 +f 21/21/21 30/30/30 29/29/29 +f 33/31/31 32/32/32 31/33/33 +f 34/34/34 32/35/32 33/36/31 +f 35/37/35 34/38/34 33/39/31 +f 36/40/36 34/41/34 35/37/35 +f 37/42/37 36/43/36 35/37/35 +f 38/44/38 36/45/36 37/42/37 +f 39/46/39 38/47/38 37/42/37 +f 40/48/40 38/49/38 39/50/39 +f 41/51/41 40/48/40 39/52/39 +f 42/53/42 40/48/40 41/54/41 +f 43/55/43 42/56/42 41/57/41 +f 44/58/44 42/59/42 43/60/43 +f 45/61/45 44/62/44 43/63/43 +f 46/64/46 44/65/44 45/61/45 +f 47/66/47 46/67/46 45/61/45 +f 48/68/48 46/69/46 47/70/47 +f 39/71/39 48/72/48 47/73/47 +f 49/74/49 48/75/48 39/76/39 +f 50/77/50 49/78/49 39/79/39 +f 51/80/51 49/81/49 50/77/50 +f 52/82/52 51/80/51 50/77/50 +f 53/83/53 51/80/51 52/82/52 +f 33/84/31 53/83/53 52/82/52 +f 31/85/33 53/83/53 33/86/31 +f 34/87/34 54/88/54 32/89/32 +f 55/90/55 54/91/54 34/92/34 +f 36/93/36 55/94/55 34/95/34 +f 56/96/56 55/97/55 36/98/36 +f 57/99/57 56/100/56 36/101/36 +f 58/102/58 56/103/56 57/104/57 +f 59/105/59 58/106/58 57/107/57 +f 60/108/60 58/109/58 59/110/59 +f 61/111/61 60/112/60 59/113/59 +f 62/114/62 60/115/60 61/116/61 +f 63/117/63 62/118/62 61/119/61 +f 64/120/64 62/121/62 63/122/63 +f 65/123/65 64/124/64 63/125/63 +f 44/126/44 64/127/64 65/128/65 +f 38/129/38 44/130/44 65/131/65 +f 42/132/42 44/133/44 38/134/38 +f 40/48/40 42/135/42 38/136/38 +f 68/137/66 67/138/67 66/139/68 +f 69/140/69 67/138/67 68/137/66 +f 70/141/70 69/140/69 68/137/66 +f 71/142/71 69/140/69 70/141/70 +f 72/143/72 71/142/71 70/141/70 +f 73/144/73 71/142/71 72/143/72 +f 74/145/74 73/144/73 72/143/72 +f 75/146/75 73/144/73 74/145/74 +f 76/147/76 75/146/75 74/145/74 +f 77/148/77 75/146/75 76/147/76 +f 78/149/78 77/148/77 76/147/76 +f 79/150/79 77/148/77 78/149/78 +f 80/151/80 79/150/79 78/149/78 +f 81/152/81 79/150/79 80/151/80 +f 82/153/82 70/141/70 68/137/66 +f 72/143/72 70/141/70 82/153/82 +f 83/154/83 72/143/72 82/153/82 +f 74/145/74 72/143/72 83/154/83 +f 84/155/84 74/145/74 83/154/83 +f 85/156/85 74/145/74 84/155/84 +f 86/157/86 85/156/85 84/155/84 +f 87/158/87 85/156/85 86/157/86 +f 88/159/88 87/158/87 86/157/86 +f 89/160/89 87/158/87 88/159/88 +f 90/161/90 89/160/89 88/159/88 +f 91/162/91 89/160/89 90/161/90 +f 92/163/92 91/162/91 90/161/90 +f 95/164/93 94/165/94 93/166/95 +f 96/167/96 94/165/94 95/164/93 +f 97/168/97 96/167/96 95/164/93 +f 98/169/98 96/167/96 97/170/97 +f 99/171/99 98/169/98 97/172/97 +f 100/173/100 98/169/98 99/171/99 +f 101/174/101 100/173/100 99/171/99 +f 102/175/102 100/173/100 101/174/101 +f 103/176/103 102/175/102 101/174/101 +f 104/177/104 102/175/102 103/176/103 +f 107/178/105 106/179/106 105/180/107 +f 108/181/108 106/182/106 107/183/105 +f 109/184/109 108/185/108 107/186/105 +f 110/187/110 108/188/108 109/189/109 +f 111/190/111 110/191/110 109/192/109 +f 112/193/112 110/194/110 111/195/111 +f 113/196/113 112/197/112 111/198/111 +f 114/199/114 112/200/112 113/201/113 +f 115/202/115 114/203/114 113/204/113 +f 116/205/116 114/206/114 115/207/115 +f 66/208/68 118/209/117 117/210/118 +f 119/211/119 118/212/117 66/213/68 +f 67/138/67 119/214/119 66/215/68 +f 120/216/120 119/217/119 67/138/67 +f 69/140/69 120/216/120 67/138/67 +f 121/218/121 120/216/120 69/140/69 +f 71/142/71 121/218/121 69/140/69 +f 122/219/122 121/218/121 71/142/71 +f 73/144/73 122/219/122 71/142/71 +f 75/146/75 122/219/122 73/144/73 +f 124/220/123 120/216/120 123/221/124 +f 119/222/119 120/216/120 124/223/123 +f 125/224/125 119/225/119 124/226/123 +f 118/227/117 119/228/119 125/229/125 +f 105/230/107 118/231/117 125/232/125 +f 117/233/118 118/234/117 105/235/107 +f 106/236/106 117/237/118 105/238/107 +f 126/239/126 117/240/118 106/241/106 +f 127/242/127 126/239/126 106/243/106 +f 128/244/128 105/245/107 125/246/125 +f 107/247/105 105/248/107 128/249/128 +f 129/250/129 107/251/105 128/252/128 +f 130/253/130 107/254/105 129/255/129 +f 131/256/131 130/257/130 129/258/129 +f 132/259/132 130/260/130 131/261/131 +f 102/262/102 132/263/132 131/264/131 +f 133/265/133 132/266/132 102/267/102 +f 1/3/3 135/268/134 134/269/135 +f 136/270/136 135/268/134 1/3/3 +f 137/271/137 136/270/136 1/3/3 +f 138/272/138 136/270/136 137/273/137 +f 139/274/139 138/272/138 137/275/137 +f 140/276/140 138/272/138 139/274/139 +f 141/277/141 140/276/140 139/274/139 +f 142/278/142 53/83/53 31/279/33 +f 143/280/143 53/83/53 142/281/142 +f 144/282/144 143/283/143 142/284/142 +f 145/285/145 143/286/143 144/282/144 +f 146/287/146 145/285/145 144/282/144 +f 147/288/147 145/285/145 146/287/146 +f 148/289/148 147/288/147 146/287/146 +f 16/16/16 8/8/8 14/14/14 +f 6/6/6 8/8/8 16/16/16 +f 18/18/18 6/6/6 16/16/16 +f 4/4/4 6/6/6 18/18/18 +f 149/290/149 4/4/4 18/18/18 +f 2/2/2 4/4/4 149/291/149 +f 150/292/150 2/2/2 149/293/149 +f 152/294/151 143/295/143 151/296/152 +f 153/297/153 143/298/143 152/299/151 +f 154/300/154 153/301/153 152/302/151 +f 51/80/51 153/303/153 154/304/154 +f 155/305/155 51/80/51 154/306/154 +f 49/307/49 51/80/51 155/308/155 +f 138/272/138 156/309/156 136/270/136 +f 157/310/157 156/311/156 138/272/138 +f 158/312/158 157/313/157 138/272/138 +f 159/314/159 157/315/157 158/316/158 +f 160/317/160 159/318/159 158/319/158 +f 161/320/161 159/321/159 160/322/160 +f 162/323/162 77/148/77 79/150/79 +f 163/324/163 77/148/77 162/323/162 +f 164/325/164 163/324/163 162/323/162 +f 165/326/165 163/324/163 164/325/164 +f 166/327/166 165/326/165 164/325/164 +f 98/328/98 165/326/165 166/327/166 +f 167/329/167 114/330/114 116/331/116 +f 168/332/168 114/333/114 167/329/167 +f 127/242/127 168/332/168 167/329/167 +f 169/334/169 168/332/168 127/242/127 +f 106/335/106 169/334/169 127/242/127 +f 108/336/108 169/334/169 106/337/106 +f 2/2/2 137/338/137 1/3/3 +f 170/339/170 137/340/137 2/2/2 +f 150/341/150 170/342/170 2/2/2 +f 171/343/171 170/344/170 150/345/150 +f 26/26/26 171/346/171 150/347/150 +f 28/28/28 171/348/171 26/26/26 +f 65/349/65 36/350/36 38/351/38 +f 57/352/57 36/353/36 65/354/65 +f 63/355/63 57/356/57 65/357/65 +f 59/358/59 57/359/57 63/360/63 +f 61/361/61 59/362/59 63/363/63 +f 131/364/131 100/365/100 102/366/102 +f 172/367/172 100/368/100 131/369/131 +f 129/370/129 172/371/172 131/372/131 +f 165/326/165 172/373/172 129/374/129 +f 123/221/124 165/326/165 129/375/129 +f 101/174/101 173/376/173 103/176/103 +f 174/377/174 173/376/173 101/174/101 +f 99/171/99 174/377/174 101/174/101 +f 175/378/175 174/377/174 99/171/99 +f 97/379/97 175/378/175 99/171/99 +f 134/380/135 79/381/79 176/382/176 +f 177/383/177 79/384/79 134/385/135 +f 135/386/134 177/387/177 134/388/135 +f 178/389/178 177/390/177 135/391/134 +f 20/20/20 26/26/26 150/392/150 +f 179/393/179 26/26/26 20/20/20 +f 22/22/22 179/394/179 20/20/20 +f 24/24/24 179/395/179 22/22/22 +f 90/161/90 180/396/180 92/163/92 +f 181/397/181 180/398/180 90/161/90 +f 88/159/88 181/399/181 90/161/90 +f 86/157/86 181/400/181 88/159/88 +f 181/401/181 182/402/182 180/403/180 +f 183/404/183 182/405/182 181/406/181 +f 86/157/86 183/407/183 181/408/181 +f 84/155/84 183/409/183 86/157/86 +f 110/410/110 169/334/169 108/411/108 +f 168/332/168 169/334/169 110/412/110 +f 112/413/112 168/332/168 110/414/110 +f 114/415/114 168/332/168 112/416/112 +f 184/417/184 55/418/55 56/419/56 +f 185/420/185 55/421/55 184/422/184 +f 64/423/64 185/424/185 184/425/184 +f 44/426/44 185/427/185 64/428/64 +f 60/429/60 56/430/56 58/431/58 +f 184/432/184 56/433/56 60/434/60 +f 62/435/62 184/436/184 60/437/60 +f 64/438/64 184/439/184 62/440/62 +f 177/441/177 162/442/162 79/443/79 +f 186/444/186 162/445/162 177/446/177 +f 178/447/178 186/448/186 177/449/177 +f 187/450/187 186/451/186 178/452/178 +f 186/453/186 164/454/164 162/455/162 +f 94/165/94 164/456/164 186/457/186 +f 187/458/187 94/165/94 186/459/186 +f 93/166/95 94/165/94 187/460/187 +f 25/25/25 29/29/29 27/27/27 +f 188/461/188 29/29/29 25/25/25 +f 23/23/23 188/462/188 25/25/25 +f 21/21/21 188/463/188 23/23/23 +f 189/464/189 170/465/170 171/466/171 +f 137/467/137 170/468/170 189/469/189 +f 139/274/139 137/470/137 189/471/189 +f 96/167/96 164/472/164 94/165/94 +f 166/473/166 164/474/164 96/167/96 +f 98/169/98 166/473/166 96/167/96 +f 89/160/89 76/147/76 87/158/87 +f 78/149/78 76/147/76 89/160/89 +f 80/151/80 78/149/78 89/160/89 +f 113/475/113 133/476/133 115/477/115 +f 132/478/132 133/479/133 113/480/113 +f 130/481/130 132/482/132 113/483/113 +f 190/484/190 128/485/128 125/486/125 +f 129/487/129 128/488/128 190/489/190 +f 123/221/124 129/490/129 190/491/190 +f 191/492/191 121/218/121 122/219/122 +f 120/216/120 121/218/121 191/493/191 +f 123/494/124 120/216/120 191/495/191 +f 37/42/37 50/77/50 39/496/39 +f 52/82/52 50/77/50 37/42/37 +f 33/497/31 52/82/52 37/42/37 +f 47/498/47 41/499/41 39/500/39 +f 43/501/43 41/502/41 47/503/47 +f 45/61/45 43/504/43 47/505/47 +f 46/506/46 155/507/155 44/508/44 +f 49/509/49 155/510/155 46/511/46 +f 48/512/48 49/513/49 46/514/46 +f 192/515/192 102/516/102 104/517/104 +f 133/518/133 102/519/102 192/520/192 +f 18/18/18 150/521/150 149/522/149 +f 20/20/20 150/523/150 18/18/18 +f 111/524/111 130/525/130 113/526/113 +f 109/527/109 130/528/130 111/529/111 +f 1/530/3 176/531/176 3/532/1 +f 134/533/135 176/531/176 1/530/3 +f 98/534/98 172/535/172 165/326/165 +f 100/536/100 172/537/172 98/538/98 +f 9/9/9 21/21/21 19/19/19 +f 7/7/7 21/21/21 9/9/9 +f 124/539/123 190/540/190 125/541/125 +f 123/221/124 190/542/190 124/543/123 +f 11/11/11 19/19/19 17/17/17 +f 9/9/9 19/19/19 11/11/11 +f 75/146/75 191/544/191 122/219/122 +f 165/326/165 191/545/191 75/146/75 +f 193/546/193 138/272/138 140/276/140 +f 158/547/158 138/272/138 193/548/193 +f 13/13/13 17/17/17 15/15/15 +f 11/11/11 17/17/17 13/13/13 +f 156/549/156 159/550/159 161/320/161 +f 157/551/157 159/552/159 156/553/156 +f 173/554/173 31/555/33 103/556/103 +f 142/557/142 31/558/33 173/559/173 +f 194/560/194 97/561/97 95/164/93 +f 175/378/175 97/562/97 194/563/194 +f 12/12/12 8/8/8 10/10/10 +f 14/14/14 8/8/8 12/12/12 +f 104/564/104 31/565/33 32/566/32 +f 103/567/103 31/568/33 104/569/104 +f 146/287/146 195/570/195 148/289/148 +f 144/282/144 195/571/195 146/287/146 +f 147/288/147 143/572/143 145/285/145 +f 151/296/152 143/573/143 147/288/147 +f 183/574/183 83/154/83 182/575/182 +f 84/155/84 83/154/83 183/576/183 +f 196/577/196 83/154/83 82/153/82 +f 182/578/182 83/154/83 196/579/196 +f 85/156/85 76/147/76 74/145/74 +f 87/158/87 76/147/76 85/156/85 +f 153/580/153 53/83/53 143/581/143 +f 51/80/51 53/83/53 153/582/153 +f 163/324/163 75/146/75 77/148/77 +f 165/326/165 75/146/75 163/324/163 +f 28/28/28 189/583/189 171/584/171 +f 30/30/30 189/585/189 28/28/28 +f 189/586/189 141/277/141 139/274/139 +f 30/30/30 141/277/141 189/587/189 +f 176/588/176 5/589/5 3/590/1 +f 176/591/176 79/150/79 81/152/81 +f 91/162/91 80/151/80 89/160/89 +f 104/592/104 32/593/32 54/594/54 +f 29/29/29 188/595/188 21/21/21 +f 179/596/179 24/24/24 26/26/26 +f 107/597/105 130/598/130 109/599/109 +f 191/600/191 165/326/165 123/494/124 +f 33/601/31 37/42/37 35/37/35 +f 185/602/185 54/603/54 55/604/55 +s 10 +f 199/605/197 198/606/198 197/607/199 +f 200/608/200 198/606/198 199/605/197 +f 201/609/201 200/608/200 199/605/197 +f 202/610/202 200/608/200 201/609/201 +f 203/611/203 202/610/202 201/609/201 +f 204/612/204 202/610/202 203/611/203 +f 205/613/205 204/612/204 203/611/203 +f 206/614/206 204/612/204 205/613/205 +f 208/615/207 199/605/197 207/616/208 +f 201/609/201 199/605/197 208/615/207 +f 209/617/209 201/609/201 208/615/207 +f 203/611/203 201/609/201 209/617/209 +f 210/618/210 203/611/203 209/617/209 +f 205/613/205 203/611/203 210/618/210 +s 11 +f 213/619/211 212/620/212 211/621/213 +f 214/622/214 212/620/212 213/619/211 +f 215/623/215 214/622/214 213/619/211 +f 216/624/216 214/622/214 215/623/215 +f 217/625/217 216/624/216 215/623/215 +f 218/626/218 216/624/216 217/625/217 +f 219/627/219 215/623/215 213/619/211 +f 220/628/220 215/623/215 219/627/219 +f 219/629/219 221/630/221 220/631/220 +f 222/632/222 221/630/221 219/629/219 +f 220/628/220 217/625/217 215/623/215 +f 225/633/223 224/634/224 223/635/225 +f 226/636/226 224/634/224 225/637/223 +f 227/638/227 226/636/226 225/639/223 +f 228/640/228 226/636/226 227/641/227 +f 229/642/229 228/640/228 227/643/227 +f 230/644/230 228/640/228 229/645/229 +f 231/646/231 230/644/230 229/647/229 +f 222/632/222 232/648/232 221/630/221 +f 233/649/233 232/648/232 222/632/222 +f 234/650/234 233/649/233 222/632/222 +f 235/651/235 233/649/233 234/650/234 +f 214/622/214 236/652/236 212/620/212 +f 231/653/231 236/654/236 214/622/214 +f 216/624/216 231/655/231 214/622/214 +f 230/644/230 231/656/231 216/624/216 +f 223/635/225 234/650/234 237/657/237 +f 235/651/235 234/650/234 223/635/225 +f 224/634/224 235/651/235 223/635/225 +f 238/658/238 233/649/233 235/651/235 +f 232/648/232 233/649/233 238/658/238 +s 10 +f 241/659/239 240/660/240 239/661/241 +f 242/662/242 240/660/240 241/663/239 +f 243/664/243 242/662/242 241/665/239 +f 244/666/244 242/662/242 243/667/243 +f 245/668/245 244/666/244 243/669/243 +f 246/670/246 244/666/244 245/668/245 +f 247/671/247 246/670/246 245/668/245 +f 248/672/248 246/670/246 247/671/247 +f 249/673/249 248/672/248 247/671/247 +f 250/674/250 248/672/248 249/673/249 +f 251/675/251 250/674/250 249/673/249 +f 252/676/252 250/674/250 251/675/251 +f 253/677/253 252/676/252 251/675/251 +f 254/678/254 252/676/252 253/679/253 +f 255/680/255 254/678/254 253/681/253 +f 256/682/256 254/678/254 255/683/255 +f 257/684/257 256/682/256 255/685/255 +f 258/686/258 256/682/256 257/687/257 +f 239/688/241 258/686/258 257/689/257 +f 240/690/240 258/686/258 239/691/241 +f 242/662/242 259/692/259 240/660/240 +f 260/693/260 259/692/259 242/662/242 +f 244/666/244 260/693/260 242/662/242 +f 261/694/261 260/693/260 244/666/244 +f 246/670/246 261/694/261 244/666/244 +f 262/695/262 261/694/261 246/670/246 +f 248/672/248 262/695/262 246/670/246 +f 263/696/263 262/695/262 248/672/248 +f 250/674/250 263/696/263 248/672/248 +f 264/697/264 263/696/263 250/674/250 +f 265/698/265 264/697/264 250/674/250 +f 266/699/266 264/697/264 265/698/265 +f 267/700/267 266/699/266 265/698/265 +f 268/701/268 266/699/266 267/700/267 +f 269/702/269 268/701/268 267/700/267 +f 270/703/270 268/701/268 269/702/269 +f 271/704/271 270/703/270 269/702/269 +f 272/705/272 268/701/268 270/703/270 +f 273/706/273 268/701/268 272/705/272 +f 274/707/274 273/706/273 272/705/272 +f 275/708/275 273/706/273 274/707/274 +f 276/709/276 275/708/275 274/707/274 +f 277/710/277 275/708/275 276/709/276 +f 278/711/278 277/710/277 276/709/276 +f 279/712/279 277/710/277 278/711/278 +f 280/713/280 279/712/279 278/711/278 +f 281/714/281 279/712/279 280/713/280 +f 282/715/282 281/714/281 280/713/280 +f 283/716/283 281/714/281 282/715/282 +f 273/706/273 266/699/266 268/701/268 +f 284/717/284 266/699/266 273/706/273 +f 275/708/275 284/717/284 273/706/273 +f 285/718/285 284/717/284 275/708/275 +f 277/710/277 285/718/285 275/708/275 +f 286/719/286 285/718/285 277/710/277 +f 279/712/279 286/719/286 277/710/277 +f 287/720/287 286/719/286 279/712/279 +f 281/714/281 287/720/287 279/712/279 +f 288/721/288 287/720/287 281/714/281 +f 283/716/283 288/721/288 281/714/281 +f 289/722/289 288/721/288 283/716/283 +f 291/723/290 243/724/243 290/725/291 +f 245/668/245 243/726/243 291/727/290 +f 292/728/292 245/668/245 291/729/290 +f 247/671/247 245/668/245 292/730/292 +f 293/731/293 247/671/247 292/732/292 +f 249/673/249 247/671/247 293/733/293 +f 294/734/294 249/673/249 293/735/293 +f 251/675/251 249/673/249 294/736/294 +f 295/737/295 251/675/251 294/738/294 +f 253/739/253 251/675/251 295/740/295 +f 284/717/284 264/697/264 266/699/266 +f 263/696/263 264/697/264 284/717/284 +f 285/718/285 263/696/263 284/717/284 +f 262/695/262 263/696/263 285/718/285 +f 286/719/286 262/695/262 285/718/285 +f 287/720/287 262/695/262 286/719/286 +f 296/741/296 283/742/283 282/743/282 +f 297/744/297 283/742/283 296/741/296 +f 298/745/298 297/744/297 296/741/296 +f 299/746/299 297/744/297 298/745/298 +f 271/704/271 299/746/299 298/745/298 +f 269/702/269 299/746/299 271/704/271 +f 297/744/297 289/747/289 283/742/283 +f 300/748/300 289/747/289 297/744/297 +f 299/746/299 300/748/300 297/744/297 +f 301/749/301 300/748/300 299/746/299 +f 269/702/269 301/749/301 299/746/299 +f 267/700/267 301/749/301 269/702/269 +f 302/750/302 256/682/256 258/686/258 +f 303/751/303 256/682/256 302/750/302 +f 267/700/267 303/751/303 302/750/302 +f 265/698/265 303/751/303 267/700/267 +f 302/750/302 301/749/301 267/700/267 +f 304/752/304 301/749/301 302/750/302 +f 258/686/258 304/752/304 302/750/302 +f 240/690/240 304/752/304 258/686/258 +f 304/752/304 300/748/300 301/749/301 +f 289/747/289 300/748/300 304/752/304 +f 259/753/259 289/747/289 304/752/304 +f 252/676/252 265/698/265 250/674/250 +f 254/678/254 265/698/265 252/676/252 +f 287/720/287 261/694/261 262/695/262 +f 288/721/288 261/694/261 287/720/287 +f 259/692/259 288/721/288 289/722/289 +f 260/693/260 288/721/288 259/692/259 +f 303/751/303 254/678/254 256/682/256 +f 265/698/265 254/678/254 303/751/303 +f 260/693/260 261/694/261 288/721/288 +f 240/690/240 259/753/259 304/752/304 +s 14 +f 307/754/305 306/755/306 305/756/307 +f 308/757/308 306/755/306 307/754/305 +f 309/758/309 308/759/308 307/754/305 +f 310/760/310 308/761/308 309/758/309 +f 311/762/311 310/760/310 309/758/309 +f 312/763/312 310/760/310 311/762/311 +f 313/764/313 312/763/312 311/762/311 +f 314/765/314 312/763/312 313/764/313 +f 315/766/315 314/765/314 313/764/313 +f 316/767/316 314/765/314 315/766/315 +f 317/768/317 316/767/316 315/766/315 +f 318/769/318 316/767/316 317/768/317 +f 319/770/319 318/769/318 317/768/317 +f 320/771/320 318/769/318 319/770/319 +f 321/772/321 320/773/320 319/770/319 +f 322/774/322 320/775/320 321/772/321 +f 324/776/323 305/756/307 323/777/324 +f 307/754/305 305/756/307 324/778/323 +f 325/779/325 307/754/305 324/780/323 +f 309/758/309 307/754/305 325/779/325 +f 326/781/326 309/758/309 325/779/325 +f 311/762/311 309/758/309 326/781/326 +f 327/782/327 311/762/311 326/781/326 +f 313/764/313 311/762/311 327/782/327 +f 328/783/328 313/764/313 327/782/327 +f 315/766/315 313/764/313 328/783/328 +f 329/784/329 315/766/315 328/783/328 +f 317/768/317 315/766/315 329/785/329 +f 330/786/330 317/768/317 329/787/329 +f 319/770/319 317/768/317 330/788/330 +f 331/789/331 319/770/319 330/790/330 +f 321/772/321 319/770/319 331/789/331 +f 334/791/332 333/792/333 332/793/334 +f 335/794/335 333/792/333 334/791/332 +f 336/795/336 335/794/335 334/791/332 +f 337/796/337 335/794/335 336/795/336 +f 338/797/338 337/798/337 336/795/336 +f 339/799/339 337/800/337 338/797/338 +f 342/801/340 341/802/341 340/803/342 +f 343/804/343 341/802/341 342/801/340 +f 344/805/344 343/804/343 342/801/340 +f 345/806/345 343/804/343 344/805/344 +f 346/807/346 345/806/345 344/805/344 +f 348/808/347 332/793/334 347/809/348 +f 334/791/332 332/793/334 348/808/347 +f 349/810/349 334/791/332 348/808/347 +f 350/811/350 334/791/332 349/812/349 +f 332/813/334 352/814/351 351/815/352 +f 353/816/353 352/814/351 332/813/334 +f 333/817/333 353/816/353 332/813/334 +f 335/818/335 353/816/353 333/817/333 +f 322/819/322 354/820/354 351/815/352 +f 355/821/355 354/820/354 322/819/322 +f 321/822/321 355/821/355 322/819/322 +f 331/823/331 355/821/355 321/822/321 +f 331/823/331 356/824/356 355/821/355 +f 342/825/340 356/824/356 331/823/331 +f 330/826/330 342/827/340 331/823/331 +f 329/828/329 342/829/340 330/830/330 +f 329/831/329 344/832/344 342/833/340 +f 357/834/357 344/835/344 329/836/329 +f 328/837/328 357/838/357 329/839/329 +f 327/840/327 357/841/357 328/837/328 +f 326/842/326 359/843/358 358/844/359 +f 335/818/335 359/845/358 326/846/326 +f 325/847/325 335/818/335 326/848/326 +f 353/816/353 335/818/335 325/847/325 +f 320/849/320 360/850/360 318/769/318 +f 361/851/361 360/852/360 320/853/320 +f 322/774/322 361/854/361 320/855/320 +f 362/856/362 361/857/361 322/774/322 +f 361/858/361 363/859/363 360/860/360 +f 364/861/364 363/862/363 361/863/361 +f 362/864/362 364/865/364 361/866/361 +f 352/867/351 364/868/364 362/869/362 +f 364/870/364 365/871/365 363/872/363 +f 366/873/366 365/874/365 364/875/364 +f 352/876/351 366/877/366 364/878/364 +f 353/879/353 366/880/366 352/881/351 +f 366/882/366 323/883/324 365/884/365 +f 324/885/323 323/886/324 366/887/366 +f 353/888/353 324/889/323 366/890/366 +f 325/779/325 324/891/323 353/892/353 +f 354/893/354 367/894/367 351/895/352 +f 368/896/368 367/897/367 354/898/354 +f 369/899/369 368/900/368 354/901/354 +f 355/902/355 369/903/369 354/904/354 +f 370/905/370 369/906/369 355/907/355 +f 340/803/342 370/908/370 355/909/355 +f 358/910/359 346/911/346 357/912/357 +f 371/913/371 346/911/346 358/914/359 +f 372/915/372 371/916/371 358/917/359 +f 356/918/356 340/803/342 355/919/355 +f 342/801/340 340/803/342 356/918/356 +f 367/920/367 332/793/334 351/921/352 +f 347/809/348 332/793/334 367/922/367 +f 350/923/350 336/795/336 334/791/332 +f 373/924/373 336/795/336 350/925/350 +f 372/926/372 337/927/337 339/799/339 +f 358/928/359 337/929/337 372/930/372 +f 359/931/358 337/932/337 358/933/359 +f 335/794/335 337/934/337 359/935/358 +f 362/936/362 351/815/352 352/814/351 +f 322/819/322 351/815/352 362/937/362 +f 327/938/327 358/939/359 357/940/357 +f 326/941/326 358/942/359 327/943/327 +f 357/944/357 346/807/346 344/805/344 +f 336/795/336 373/924/373 338/797/338 +s 11 +f 237/945/237 225/946/223 223/635/225 +f 374/947/374 225/948/223 237/949/237 +f 375/950/375 374/951/374 237/952/237 +f 376/953/376 374/954/374 375/955/375 +f 379/956/377 378/957/378 377/958/379 +f 380/959/380 378/960/378 379/961/377 +f 229/962/229 380/963/380 379/964/377 +f 227/965/227 380/966/380 229/967/229 +f 380/968/380 376/969/376 378/970/378 +f 374/971/374 376/972/376 380/973/380 +f 227/974/227 374/975/374 380/976/380 +f 225/977/223 374/978/374 227/979/227 +f 379/980/377 231/981/231 229/982/229 +f 236/983/236 231/984/231 379/985/377 +f 211/621/213 382/986/381 381/987/382 +f 383/988/383 382/986/381 211/621/213 +f 212/620/212 383/989/383 211/621/213 +f 236/990/236 383/991/383 212/620/212 +f 383/992/383 384/993/384 382/986/381 +f 377/994/379 384/993/384 383/995/383 +f 236/996/236 377/997/379 383/998/383 +f 379/999/377 377/1000/379 236/1001/236 +f 385/1002/385 376/1003/376 375/1004/375 +f 386/1005/386 376/1006/376 385/1002/385 +f 386/1005/386 378/1007/378 376/1008/376 +f 387/1009/387 378/1010/378 386/1005/386 +f 387/1009/387 377/1011/379 378/1012/378 +f 384/993/384 377/1013/379 387/1009/387 +s 10 +f 390/1014/388 389/1015/389 388/1016/390 +f 391/1017/391 389/1018/389 390/1014/388 +f 392/1019/392 391/1017/391 390/1014/388 +f 393/1020/393 391/1017/391 392/1019/392 +f 394/1021/394 393/1020/393 392/1019/392 +f 395/1022/395 393/1020/393 394/1021/394 +f 396/1023/396 395/1022/395 394/1021/394 +f 397/1024/397 395/1022/395 396/1023/396 +f 398/1025/398 397/1024/397 396/1023/396 +s 14 +f 370/1026/370 399/1027/399 369/1028/369 +f 400/1029/400 399/1027/399 370/1030/370 +f 340/803/342 400/1029/400 370/1031/370 +f 401/1032/401 400/1029/400 340/803/342 +f 402/1033/402 401/1032/401 340/803/342 +f 403/1034/403 401/1032/401 402/1035/402 +f 404/1036/404 403/1034/403 402/1037/402 +f 405/1038/405 403/1034/403 404/1036/404 +f 400/1029/400 406/1039/406 399/1027/399 +f 407/1040/407 406/1041/406 400/1029/400 +f 401/1032/401 407/1042/407 400/1029/400 +f 408/1043/408 407/1044/407 401/1032/401 +f 403/1034/403 408/1043/408 401/1032/401 +f 409/1045/409 408/1043/408 403/1034/403 +f 405/1038/405 409/1045/409 403/1034/403 +f 410/1046/410 409/1045/409 405/1038/405 +s 11 +f 413/1047/411 412/1048/412 411/1049/413 +f 414/1050/414 412/1051/412 413/1052/411 +f 415/1053/415 414/1054/414 413/1055/411 +f 416/1056/416 414/1057/414 415/1058/415 +f 417/1059/417 416/1060/416 415/1061/415 +f 418/1062/418 416/1063/416 417/1064/417 +f 419/1065/419 418/1066/418 417/1067/417 +s 14 +f 407/1068/407 420/1069/420 406/1070/406 +f 421/1071/421 420/1072/420 407/1073/407 +f 408/1043/408 421/1074/421 407/1075/407 +f 422/1076/422 421/1077/421 408/1043/408 +f 409/1045/409 422/1076/422 408/1043/408 +f 423/1078/423 350/1079/350 349/1080/349 +f 373/924/373 350/1081/350 423/1078/423 +f 424/1082/424 373/924/373 423/1078/423 +f 425/1083/425 373/924/373 424/1082/424 +f 426/1084/426 409/1045/409 410/1046/410 +f 422/1076/422 409/1045/409 426/1084/426 +f 427/1085/427 422/1076/422 426/1084/426 +f 428/1086/428 422/1076/422 427/1085/427 +f 421/1087/421 429/1088/429 420/1089/420 +f 428/1090/428 429/1091/429 421/1092/421 +f 422/1076/422 428/1093/428 421/1094/421 +f 402/1095/402 430/1096/430 404/1036/404 +f 341/802/341 430/1097/430 402/1098/402 +f 340/803/342 341/802/341 402/1099/402 +s 11 +f 381/987/382 419/1100/419 431/1101/431 +f 418/1102/418 419/1103/419 381/987/382 +s 14 +f 338/797/338 425/1104/425 339/799/339 +f 373/924/373 425/1105/425 338/797/338 +f 341/802/341 343/804/343 430/1106/430 +s 11 +f 434/1107/432 433/1108/433 432/1109/434 +f 435/1110/435 433/1111/433 434/1112/432 +f 436/1113/436 435/1114/435 434/1115/432 +f 437/1116/437 435/1117/435 436/1118/436 +f 438/1119/438 437/1120/437 436/1121/436 +f 439/1122/439 437/1123/437 438/1124/438 +f 440/1125/440 439/1126/439 438/1127/438 +f 441/1128/441 439/1129/439 440/1130/440 +f 442/1131/442 441/1132/441 440/1133/440 +f 443/1134/443 441/1135/441 442/1136/442 +f 444/1137/444 443/1138/443 442/1139/442 +f 445/1140/445 443/1141/443 444/1142/444 +f 446/1143/446 445/1144/445 444/1145/444 +f 447/1146/447 445/1147/445 446/1148/446 +f 448/1149/448 447/1150/447 446/1151/446 +f 449/1152/449 447/1153/447 448/1154/448 +f 450/1155/450 449/1156/449 448/1157/448 +f 453/1158/451 452/1159/452 451/1160/453 +f 454/1161/454 452/1162/452 453/1163/451 +f 455/1164/455 454/1165/454 453/1166/451 +f 456/1167/456 454/1168/454 455/1169/455 +f 457/1170/457 456/1171/456 455/1172/455 +f 458/1173/458 456/1174/456 457/1175/457 +f 459/1176/459 458/1177/458 457/1178/457 +f 436/1179/436 458/1180/458 459/1181/459 +f 460/1182/460 436/1183/436 459/1184/459 +f 438/1185/438 436/1186/436 460/1187/460 +f 461/1188/461 438/1189/438 460/1190/460 +f 462/1191/462 438/1192/438 461/1193/461 +f 238/658/238 462/1194/462 461/1195/461 +f 463/1196/463 462/1197/462 238/658/238 +f 235/651/235 463/1198/463 238/658/238 +f 224/634/224 463/1199/463 235/651/235 +f 466/1200/464 465/1201/465 464/1202/466 +f 467/1203/467 465/1204/465 466/1205/464 +f 468/1206/468 467/1207/467 466/1208/464 +f 469/1209/469 467/1210/467 468/1211/468 +f 443/1212/443 469/1213/469 468/1214/468 +f 470/1215/470 469/1216/469 443/1217/443 +f 445/1218/445 470/1219/470 443/1220/443 +f 471/1221/471 470/1222/470 445/1223/445 +f 447/1224/447 471/1225/471 445/1226/445 +f 449/1227/449 471/1228/471 447/1229/447 +f 435/1230/435 472/1231/472 433/1232/433 +f 473/1233/473 472/1234/472 435/1235/435 +f 437/1236/437 473/1237/473 435/1238/435 +f 474/1239/474 473/1240/473 437/1241/437 +f 439/1242/439 474/1243/474 437/1244/437 +f 441/1245/441 474/1246/474 439/1247/439 +f 473/1248/473 464/1249/466 472/1250/472 +f 466/1251/464 464/1252/466 473/1253/473 +f 474/1254/474 466/1255/464 473/1256/473 +f 468/1257/468 466/1258/464 474/1259/474 +f 441/1260/441 468/1261/468 474/1262/474 +f 443/1263/443 468/1264/468 441/1265/441 +f 476/1266/475 451/1267/453 475/1268/476 +f 453/1269/451 451/1270/453 476/1271/475 +f 471/1272/471 453/1273/451 476/1274/475 +f 455/1275/455 453/1276/451 471/1277/471 +f 449/1278/449 455/1279/455 471/1280/471 +f 477/1281/477 224/634/224 226/636/226 +f 463/1282/463 224/634/224 477/1283/477 +f 440/1284/440 463/1285/463 477/1286/477 +f 462/1287/462 463/1288/463 440/1289/440 +f 438/1290/438 462/1291/462 440/1292/440 +f 478/1293/478 220/631/220 221/630/221 +f 450/1294/450 220/631/220 478/1295/478 +f 457/1296/457 450/1297/450 478/1298/478 +f 449/1299/449 450/1300/450 457/1301/457 +f 455/1302/455 449/1303/449 457/1304/457 +f 454/1305/454 479/1306/479 452/1307/452 +f 480/1308/480 479/1309/479 454/1310/454 +f 456/1311/456 480/1312/480 454/1313/454 +f 458/1314/458 480/1315/480 456/1316/456 +f 480/1317/480 432/1318/434 479/1319/479 +f 434/1320/432 432/1321/434 480/1322/480 +f 458/1323/458 434/1324/432 480/1325/480 +f 436/1326/436 434/1327/432 458/1328/458 +f 467/1329/467 481/1330/481 465/1331/465 +f 482/1332/482 481/1333/481 467/1334/467 +f 469/1335/469 482/1336/482 467/1337/467 +f 470/1338/470 482/1339/482 469/1340/469 +f 482/1341/482 475/1342/476 481/1343/481 +f 476/1344/475 475/1345/476 482/1346/482 +f 470/1347/470 476/1348/475 482/1349/482 +f 471/1350/471 476/1351/475 470/1352/470 +f 218/626/218 230/644/230 216/624/216 +f 483/1353/483 230/644/230 218/626/218 +f 446/1354/446 483/1355/483 218/626/218 +f 444/1356/444 483/1357/483 446/1358/446 +f 483/1359/483 228/640/228 230/644/230 +f 484/1360/484 228/640/228 483/1361/483 +f 444/1362/444 484/1363/484 483/1364/483 +f 442/1365/442 484/1366/484 444/1367/444 +f 484/1368/484 226/636/226 228/640/228 +f 477/1369/477 226/636/226 484/1370/484 +f 442/1371/442 477/1372/477 484/1373/484 +f 440/1374/440 477/1375/477 442/1376/442 +f 461/1377/461 232/648/232 238/658/238 +f 485/1378/485 232/648/232 461/1379/461 +f 460/1380/460 485/1381/485 461/1382/461 +f 459/1383/459 485/1384/485 460/1385/460 +f 485/1386/485 221/630/221 232/648/232 +f 478/1387/478 221/630/221 485/1388/485 +f 459/1389/459 478/1390/478 485/1391/485 +f 457/1392/457 478/1393/478 459/1394/459 +s 14 +f 424/1082/424 486/1395/486 425/1396/425 +f 423/1078/423 486/1395/486 424/1082/424 +s 11 +f 450/1397/450 217/625/217 220/628/220 +f 448/1398/448 217/625/217 450/1399/450 +f 448/1400/448 218/626/218 217/625/217 +f 446/1401/446 218/626/218 448/1402/448 +s 14 +f 428/1403/428 487/1404/487 429/1405/429 +f 488/1406/488 487/1404/487 428/1407/428 +f 427/1085/427 488/1406/488 428/1408/428 +f 489/1409/489 488/1406/488 427/1085/427 +f 490/1410/490 489/1409/489 427/1085/427 +f 491/1411/491 489/1409/489 490/1412/490 +f 492/1413/492 491/1411/491 490/1414/490 +s 11 +f 381/987/382 493/1415/493 211/621/213 +f 494/1416/494 493/1415/493 381/987/382 +f 431/1417/431 494/1416/494 381/987/382 +f 495/1418/495 494/1416/494 431/1419/431 +s 14 +f 490/1420/490 496/1421/496 492/1413/492 +f 497/1422/497 496/1421/496 490/1423/490 +f 426/1084/426 497/1424/497 490/1425/490 +f 410/1046/410 497/1426/497 426/1084/426 +f 491/1411/491 488/1406/488 489/1409/489 +f 498/1427/498 488/1406/488 491/1411/491 +f 499/1428/499 488/1406/488 498/1429/498 +f 487/1404/487 488/1406/488 499/1430/499 +f 426/1084/426 490/1431/490 427/1085/427 +s 10 +f 502/1432/500 501/1433/501 500/1434/502 +f 503/1435/503 501/1433/501 502/1432/500 +f 504/1436/504 503/1435/503 502/1432/500 +f 505/1437/505 503/1435/503 504/1436/504 +f 506/1438/506 505/1437/505 504/1436/504 +f 507/1439/507 505/1437/505 506/1440/506 +f 509/1441/508 501/1442/501 508/1443/509 +f 510/1444/510 501/1442/501 509/1441/508 +f 511/1445/511 510/1444/510 509/1441/508 +f 512/1446/512 510/1444/510 511/1445/511 +f 514/1447/513 505/1437/505 513/1448/514 +f 503/1435/503 505/1437/505 514/1447/513 +f 508/1449/509 503/1435/503 514/1447/513 +f 501/1433/501 503/1435/503 508/1449/509 +f 515/1450/515 510/1444/510 512/1446/512 +f 500/1451/502 510/1444/510 515/1450/515 +f 513/1452/514 507/1453/507 516/1454/516 +f 505/1437/505 507/1455/507 513/1452/514 +f 501/1442/501 510/1444/510 500/1451/502 +f 502/1432/500 517/1456/517 504/1436/504 +f 509/1441/508 518/1457/518 511/1445/511 +f 519/1458/519 518/1457/518 509/1441/508 +f 508/1443/509 519/1458/519 509/1441/508 +f 520/1459/520 519/1458/519 508/1443/509 +f 523/1460/521 522/1461/522 521/1462/523 +f 524/1463/524 522/1464/522 523/1465/521 +f 520/1466/520 524/1463/524 523/1467/521 +f 519/1458/519 525/1468/525 518/1457/518 +f 526/1469/526 525/1470/525 519/1458/519 +f 527/1471/527 526/1472/526 519/1458/519 +f 524/1473/524 514/1447/513 513/1448/514 +f 520/1474/520 514/1447/513 524/1473/524 +f 516/1475/516 524/1463/524 513/1452/514 +f 522/1476/522 524/1463/524 516/1477/516 +f 527/1478/527 520/1466/520 523/1479/521 +f 508/1449/509 514/1447/513 520/1474/520 +f 520/1459/520 527/1480/527 519/1458/519 +f 525/1481/525 528/1482/528 197/607/199 +f 295/1483/295 528/1484/528 525/1485/525 +f 529/1486/529 295/1487/295 525/1488/525 +f 253/1489/253 295/1490/295 529/1491/529 +f 255/1492/255 253/1493/253 529/1494/529 +f 526/1495/526 529/1496/529 525/1497/525 +f 255/1498/255 529/1499/529 526/1500/526 +f 257/1501/257 255/1502/255 526/1503/526 +f 518/1457/518 197/607/199 198/606/198 +f 525/1504/525 197/607/199 518/1457/518 +f 294/1505/294 528/1506/528 295/1507/295 +f 207/616/208 528/1508/528 294/1509/294 +f 293/1510/293 207/616/208 294/1511/294 +f 208/615/207 207/616/208 293/1512/293 +f 292/1513/292 208/615/207 293/1514/293 +f 209/617/209 208/615/207 292/1515/292 +f 291/1516/290 209/617/209 292/1517/292 +f 210/618/210 209/617/209 291/1518/290 +f 290/1519/291 210/618/210 291/1520/290 +f 530/1521/530 210/618/210 290/1522/291 +f 531/1523/531 530/1524/530 290/1525/291 +f 523/1526/521 530/1527/530 531/1528/531 +f 527/1529/527 523/1530/521 531/1531/531 +f 531/1532/531 239/1533/241 527/1534/527 +f 241/1535/239 239/1536/241 531/1537/531 +f 290/1538/291 241/1539/239 531/1540/531 +f 243/1541/243 241/1542/239 290/1543/291 +f 521/1544/523 530/1545/530 523/1546/521 +f 205/613/205 530/1547/530 521/1548/523 +f 207/616/208 197/607/199 528/1549/528 +f 199/605/197 197/607/199 207/616/208 +f 257/1550/257 527/1551/527 239/1552/241 +f 526/1553/526 527/1554/527 257/1555/257 +f 210/618/210 530/1556/530 205/613/205 +s 11 +f 213/619/211 532/1557/532 219/627/219 +f 533/1558/533 532/1559/532 213/619/211 +f 211/621/213 533/1560/533 213/619/211 +f 493/1415/493 533/1561/533 211/621/213 +f 535/1562/534 533/1563/533 534/1564/535 +f 532/1565/532 533/1566/533 535/1567/534 +f 536/1568/536 532/1569/532 535/1570/534 +f 222/632/222 537/1571/537 234/650/234 +f 219/629/219 537/1572/537 222/632/222 +f 532/1573/532 537/1574/537 219/629/219 +f 536/1575/536 537/1576/537 532/1577/532 +f 538/1578/538 537/1579/537 536/1580/536 +f 534/1581/535 533/1582/533 493/1415/493 +f 541/1583/539 540/1584/540 539/1585/541 +f 542/1586/542 540/1587/540 541/1588/539 +f 536/1589/536 542/1590/542 541/1591/539 +f 535/1592/534 542/1593/542 536/1594/536 +f 541/1595/539 538/1596/538 536/1597/536 +f 543/1598/543 538/1599/538 541/1600/539 +f 539/1601/541 543/1602/543 541/1603/539 +f 544/1604/544 543/1605/543 539/1606/541 +f 545/1607/545 535/1608/534 534/1609/535 +f 542/1610/542 535/1611/534 545/1612/545 +f 546/1613/546 542/1614/542 545/1615/545 +f 547/1616/547 542/1617/542 546/1618/546 +f 545/1619/545 495/1418/495 546/1620/546 +f 494/1416/494 495/1418/495 545/1621/545 +f 534/1622/535 494/1416/494 545/1623/545 +f 493/1415/493 494/1416/494 534/1624/535 +f 543/1625/543 548/1626/548 538/1627/538 +f 549/1628/549 548/1629/548 543/1630/543 +f 544/1631/544 549/1632/549 543/1633/543 +f 547/1634/547 540/1635/540 542/1636/542 +s 10 +f 398/1025/398 550/1637/550 397/1024/397 +f 551/1638/551 550/1637/550 398/1025/398 +s 11 +f 553/1639/552 552/1640/553 411/1641/413 +f 548/1642/548 552/1643/553 553/1644/552 +s 10 +f 551/1638/551 511/1445/511 550/1637/550 +f 512/1446/512 511/1445/511 551/1638/551 +s 11 +f 548/1645/548 549/1646/549 552/1647/553 +s 10 +f 518/1457/518 550/1637/550 511/1445/511 +f 554/1648/554 550/1637/550 518/1457/518 +f 198/606/198 554/1649/554 518/1457/518 +f 200/608/200 554/1650/554 198/606/198 +f 200/608/200 555/1651/555 554/1652/554 +f 202/610/202 555/1653/555 200/608/200 +f 202/610/202 556/1654/556 555/1655/555 +f 204/612/204 556/1656/556 202/610/202 +f 204/612/204 557/1657/557 556/1658/556 +f 206/614/206 557/1659/557 204/612/204 +f 206/614/206 558/1660/558 557/1661/557 +f 507/1662/507 389/1663/389 516/1664/516 +f 388/1016/390 389/1665/389 507/1666/507 +f 506/1667/506 388/1016/390 507/1668/507 +f 554/1669/554 397/1024/397 550/1637/550 +f 555/1670/555 397/1024/397 554/1671/554 +f 555/1672/555 395/1022/395 397/1024/397 +f 556/1673/556 395/1022/395 555/1674/555 +f 556/1675/556 393/1020/393 395/1022/395 +f 557/1676/557 393/1020/393 556/1677/556 +f 557/1678/557 391/1017/391 393/1020/393 +f 558/1679/558 391/1017/391 557/1680/557 +f 558/1681/558 389/1682/389 391/1017/391 +f 516/1683/516 389/1684/389 558/1685/558 +f 558/1686/558 522/1687/522 516/1688/516 +f 206/614/206 522/1689/522 558/1690/558 +f 206/614/206 521/1691/523 522/1692/522 +f 205/613/205 521/1693/523 206/614/206 +s 11 +f 412/1694/412 553/1695/552 411/1696/413 +f 385/1002/385 553/1697/552 412/1698/412 +f 386/1005/386 385/1002/385 412/1699/412 +f 385/1002/385 559/1700/559 553/1701/552 +f 375/1702/375 559/1703/559 385/1002/385 +f 382/986/381 418/1704/418 381/987/382 +f 384/993/384 418/1705/418 382/986/381 +f 384/993/384 416/1706/416 418/1707/418 +f 387/1009/387 416/1708/416 384/993/384 +f 387/1009/387 414/1709/414 416/1710/416 +f 386/1005/386 414/1711/414 387/1009/387 +f 412/1712/412 414/1713/414 386/1005/386 +f 559/1714/559 548/1715/548 553/1716/552 +f 538/1717/538 548/1718/548 559/1719/559 +f 537/1720/537 538/1721/538 559/1722/559 +f 559/1723/559 234/650/234 537/1724/537 +f 237/1725/237 234/650/234 559/1726/559 +f 375/1727/375 237/1728/237 559/1729/559 +s 34 +f 562/1730/560 561/1731/561 560/1732/562 +f 563/1733/563 561/1731/561 562/1730/560 +f 564/1734/564 563/1733/563 562/1730/560 +f 565/1735/565 563/1733/563 564/1734/564 +f 566/1736/566 565/1735/565 564/1734/564 +f 567/1737/567 565/1735/565 566/1736/566 +f 568/1738/568 567/1737/567 566/1736/566 +f 569/1739/569 567/1737/567 568/1738/568 +f 570/1740/570 569/1739/569 568/1738/568 +f 573/1741/571 572/1742/572 571/1743/573 +f 574/1744/574 572/1745/572 573/1746/571 +f 575/1747/575 574/1748/574 573/1749/571 +f 576/1750/576 574/1751/574 575/1752/575 +f 577/1753/577 576/1754/576 575/1755/575 +f 578/1756/578 576/1757/576 577/1758/577 +f 579/1759/579 578/1760/578 577/1761/577 +f 580/1762/580 578/1763/578 579/1764/579 +f 581/1765/581 580/1766/580 579/1767/579 +f 584/1768/582 583/1769/583 582/1770/584 +f 585/1771/585 583/1769/583 584/1768/582 +f 586/1772/586 585/1771/585 584/1768/582 +f 587/1773/587 585/1771/585 586/1772/586 +f 588/1774/588 587/1773/587 586/1772/586 +f 589/1775/589 587/1773/587 588/1774/588 +f 590/1776/590 589/1775/589 588/1774/588 +f 591/1777/591 589/1775/589 590/1776/590 +f 594/1778/592 593/1779/593 592/1780/594 +f 595/1781/595 593/1779/593 594/1778/592 +f 596/1782/596 595/1781/595 594/1778/592 +f 597/1783/597 595/1781/595 596/1782/596 +f 598/1784/598 597/1783/597 596/1782/596 +f 599/1785/599 597/1783/597 598/1784/598 +f 600/1786/600 599/1785/599 598/1784/598 +f 601/1787/601 599/1785/599 600/1786/600 +f 593/1779/593 603/1788/602 602/1789/603 +f 604/1790/604 603/1788/602 593/1779/593 +f 595/1781/595 604/1790/604 593/1779/593 +f 605/1791/605 604/1790/604 595/1781/595 +f 597/1783/597 605/1791/605 595/1781/595 +f 590/1776/590 605/1791/605 597/1783/597 +f 599/1785/599 590/1776/590 597/1783/597 +f 601/1787/601 590/1776/590 599/1785/599 +f 606/1792/606 589/1775/589 591/1777/591 +f 587/1773/587 589/1775/589 606/1792/606 +f 607/1793/607 587/1773/587 606/1792/606 +f 585/1771/585 587/1773/587 607/1793/607 +f 608/1794/608 585/1771/585 607/1793/607 +f 583/1769/583 585/1771/585 608/1794/608 +f 609/1795/609 566/1736/566 564/1734/564 +f 610/1796/610 566/1736/566 609/1797/609 +f 611/1798/611 610/1799/610 609/1800/609 +f 612/1801/612 610/1802/610 611/1798/611 +f 610/1803/610 568/1738/568 566/1736/566 +f 613/1804/613 568/1738/568 610/1805/610 +f 612/1801/612 613/1806/613 610/1807/610 +f 608/1808/608 613/1809/613 612/1801/612 +f 614/1810/614 577/1811/577 575/1812/575 +f 615/1813/615 577/1814/577 614/1815/614 +f 602/1816/603 615/1817/615 614/1818/614 +f 603/1819/602 615/1820/615 602/1821/603 +f 615/1822/615 579/1823/579 577/1824/577 +f 616/1825/616 579/1826/579 615/1827/615 +f 603/1828/602 616/1829/616 615/1830/615 +f 604/1831/604 616/1832/616 603/1833/602 +f 619/1834/617 618/1835/618 617/1836/619 +f 620/1837/620 618/1838/618 619/1839/617 +f 621/1840/621 620/1841/620 619/1842/617 +f 622/1843/622 620/1844/620 621/1845/621 +f 622/1843/622 623/1846/623 620/1847/620 +f 624/1848/624 623/1846/623 622/1843/622 +f 625/1849/625 624/1848/624 622/1843/622 +f 600/1786/600 624/1848/624 625/1849/625 +f 609/1850/609 560/1851/562 611/1852/611 +f 562/1730/560 560/1853/562 609/1854/609 +f 564/1734/564 562/1730/560 609/1855/609 +f 614/1856/614 571/1857/573 602/1858/603 +f 573/1859/571 571/1860/573 614/1861/614 +f 575/1862/575 573/1863/571 614/1864/614 +f 581/1865/581 567/1737/567 569/1739/569 +f 590/1866/590 567/1737/567 581/1867/581 +f 605/1868/605 590/1869/590 581/1870/581 +f 607/1871/607 613/1872/613 608/1808/608 +f 570/1740/570 613/1873/613 607/1874/607 +f 606/1875/606 570/1740/570 607/1876/607 +f 578/1877/578 598/1878/598 596/1879/596 +f 600/1880/600 598/1881/598 578/1882/578 +f 617/1883/619 600/1884/600 578/1885/578 +f 617/1836/619 626/1886/626 600/1887/600 +f 627/1888/627 626/1886/626 617/1836/619 +f 618/1889/618 627/1888/627 617/1836/619 +f 628/1890/628 600/1786/600 626/1891/626 +f 624/1848/624 600/1786/600 628/1890/628 +f 623/1846/623 624/1848/624 628/1890/628 +f 583/1769/583 611/1892/611 560/1893/562 +f 612/1894/612 611/1892/611 583/1769/583 +f 608/1794/608 612/1894/612 583/1769/583 +f 593/1779/593 572/1895/572 592/1780/594 +f 571/1896/573 572/1895/572 593/1779/593 +f 602/1789/603 571/1896/573 593/1779/593 +f 563/1733/563 584/1897/582 582/1898/584 +f 565/1735/565 584/1899/582 563/1733/563 +f 574/1900/574 594/1901/592 592/1902/594 +f 576/1903/576 594/1904/592 574/1905/574 +f 605/1906/605 616/1907/616 604/1908/604 +f 581/1909/581 616/1910/616 605/1911/605 +f 576/1912/576 596/1913/596 594/1914/592 +f 578/1915/578 596/1916/596 576/1917/576 +f 565/1735/565 586/1918/586 584/1919/582 +f 567/1737/567 586/1920/586 565/1735/565 +f 567/1737/567 588/1921/588 586/1922/586 +f 590/1923/590 588/1924/588 567/1737/567 +f 561/1925/561 583/1769/583 560/1893/562 +f 582/1770/584 583/1769/583 561/1925/561 +f 561/1731/561 563/1733/563 582/1926/584 +f 572/1927/572 574/1928/574 592/1929/594 +f 568/1738/568 613/1930/613 570/1740/570 +f 580/1931/580 617/1932/619 578/1933/578 +f 579/1934/579 616/1935/616 581/1936/581 +f 631/1937/629 630/1938/630 629/1939/631 +f 632/1940/632 630/1938/630 631/1937/629 +f 633/1941/633 632/1940/632 631/1937/629 +f 634/1942/634 632/1940/632 633/1941/633 +f 635/1943/635 634/1942/634 633/1941/633 +f 636/1944/636 634/1942/634 635/1943/635 +f 637/1945/637 636/1944/636 635/1943/635 +f 638/1946/638 636/1944/636 637/1945/637 +f 639/1947/639 638/1946/638 637/1945/637 +f 640/1948/640 638/1946/638 639/1947/639 +f 641/1949/641 640/1948/640 639/1947/639 +f 642/1950/642 640/1948/640 641/1949/641 +f 643/1951/643 642/1950/642 641/1949/641 +f 644/1952/644 642/1950/642 643/1951/643 +f 647/1953/645 646/1954/646 645/1955/647 +f 648/1956/648 646/1954/646 647/1953/645 +f 649/1957/649 648/1956/648 647/1953/645 +f 650/1958/650 648/1956/648 649/1957/649 +f 651/1959/651 650/1958/650 649/1957/649 +f 652/1960/652 650/1958/650 651/1959/651 +f 630/1938/630 652/1960/652 651/1959/651 +f 632/1940/632 652/1960/652 630/1938/630 +f 643/1961/643 629/1962/631 644/1963/644 +f 631/1937/629 629/1962/631 643/1961/643 +f 653/1964/653 631/1937/629 643/1961/643 +f 633/1941/633 631/1937/629 653/1964/653 +f 654/1965/654 633/1941/633 653/1964/653 +f 635/1943/635 633/1941/633 654/1965/654 +f 637/1966/637 635/1943/635 654/1965/654 +f 655/1967/655 642/1950/642 646/1954/646 +f 640/1948/640 642/1950/642 655/1967/655 +f 656/1968/656 640/1948/640 655/1967/655 +f 638/1946/638 640/1948/640 656/1968/656 +f 636/1944/636 638/1946/638 656/1968/656 +f 629/1969/631 622/1843/622 621/1970/621 +f 657/1971/657 622/1843/622 629/1969/631 +f 630/1972/630 657/1971/657 629/1969/631 +f 651/1973/651 657/1971/657 630/1972/630 +f 658/1974/658 642/1950/642 644/1952/644 +f 646/1954/646 642/1950/642 658/1974/658 +f 659/1975/659 646/1954/646 658/1974/658 +f 645/1955/647 646/1954/646 659/1975/659 +f 641/1976/641 653/1964/653 643/1961/643 +f 660/1977/660 653/1964/653 641/1976/641 +f 639/1978/639 660/1977/660 641/1976/641 +f 637/1966/637 660/1977/660 639/1978/639 +f 656/1968/656 634/1942/634 636/1944/636 +f 661/1979/661 634/1942/634 656/1968/656 +f 655/1967/655 661/1979/661 656/1968/656 +f 650/1958/650 661/1979/661 655/1967/655 +f 657/1971/657 662/1980/662 622/1843/622 +f 663/1981/663 662/1980/662 657/1971/657 +f 651/1973/651 663/1981/663 657/1971/657 +f 619/1982/617 629/1983/631 621/1984/621 +f 644/1952/644 629/1985/631 619/1986/617 +f 654/1965/654 660/1977/660 637/1966/637 +f 653/1964/653 660/1977/660 654/1965/654 +f 648/1956/648 655/1967/655 646/1954/646 +f 650/1958/650 655/1967/655 648/1956/648 +f 652/1960/652 661/1979/661 650/1958/650 +f 632/1940/632 661/1979/661 652/1960/652 +f 634/1942/634 661/1979/661 632/1940/632 +s 42 +f 666/1987/664 665/1988/665 664/1989/666 +f 667/1990/667 665/1988/665 666/1987/664 +f 668/1991/668 667/1990/667 666/1987/664 +f 669/1992/669 667/1990/667 668/1991/668 +f 670/1993/670 669/1992/669 668/1991/668 +f 671/1994/671 669/1992/669 670/1993/670 +f 672/1995/672 671/1994/671 670/1993/670 +f 673/1996/673 671/1994/671 672/1995/672 +f 674/1997/674 673/1996/673 672/1995/672 +f 675/1998/675 673/1996/673 674/1997/674 +f 676/1999/676 675/1998/675 674/1997/674 +f 677/2000/677 675/1998/675 676/1999/676 +f 678/2001/678 677/2000/677 676/1999/676 +f 679/2002/679 677/2000/677 678/2001/678 +f 664/1989/666 679/2002/679 678/2001/678 +f 665/1988/665 679/2002/679 664/1989/666 +s 43 +f 682/2003/680 681/2004/681 680/2005/682 +f 683/2006/683 681/2007/681 682/2008/680 +f 684/2009/684 683/2010/683 682/2011/680 +f 685/2012/685 683/2013/683 684/2014/684 +f 686/2015/686 685/2016/685 684/2017/684 +f 687/2018/687 685/2019/685 686/2020/686 +f 688/2021/688 687/2022/687 686/2023/686 +f 689/2024/689 687/2025/687 688/2026/688 +f 690/2027/690 689/2028/689 688/2029/688 +f 691/2030/691 689/2031/689 690/2032/690 +f 692/2033/692 691/2034/691 690/2035/690 +f 693/2036/693 691/2037/691 692/2038/692 +f 694/2039/694 693/2040/693 692/2041/692 +f 695/2042/695 693/2043/693 694/2044/694 +f 680/2045/682 695/2046/695 694/2047/694 +f 681/2048/681 695/2049/695 680/2050/682 +s 44 +f 698/2051/696 697/2052/697 696/2053/698 +f 699/2054/699 697/2052/697 698/2051/696 +f 700/2055/700 699/2054/699 698/2051/696 +f 701/2056/701 699/2054/699 700/2055/700 +f 702/2057/702 701/2056/701 700/2055/700 +f 703/2058/703 701/2056/701 702/2057/702 +f 704/2059/704 703/2058/703 702/2057/702 +f 705/2060/705 703/2058/703 704/2059/704 +f 706/2061/706 705/2060/705 704/2059/704 +f 707/2062/707 705/2060/705 706/2061/706 +f 708/2063/708 707/2062/707 706/2061/706 +f 709/2064/709 707/2062/707 708/2063/708 +f 710/2065/710 709/2064/709 708/2063/708 +f 711/2066/711 709/2064/709 710/2065/710 +f 696/2053/698 711/2066/711 710/2065/710 +f 697/2052/697 711/2066/711 696/2053/698 +s 34 +f 714/2067/712 713/2068/713 712/2069/714 +f 715/2070/715 713/2068/713 714/2067/712 +f 716/2071/716 715/2070/715 714/2067/712 +f 717/2072/717 715/2070/715 716/2071/716 +f 718/2073/718 717/2072/717 716/2071/716 +f 719/2074/719 717/2072/717 718/2073/718 +f 720/2075/720 719/2074/719 718/2073/718 +f 721/2076/721 719/2074/719 720/2075/720 +f 722/2077/722 721/2076/721 720/2075/720 +f 723/2078/723 721/2076/721 722/2077/722 +f 724/2079/724 723/2078/723 722/2077/722 +f 725/2080/725 723/2078/723 724/2079/724 +f 726/2081/726 725/2080/725 724/2079/724 +f 727/2082/727 725/2080/725 726/2081/726 +f 728/2083/728 727/2082/727 726/2081/726 +f 712/2069/714 569/2084/569 570/2085/570 +f 729/2086/729 569/2084/569 712/2069/714 +f 713/2068/713 729/2086/729 712/2069/714 +f 730/2087/730 729/2086/729 713/2068/713 +f 731/2088/731 730/2087/730 713/2068/713 +f 732/2089/732 730/2087/730 731/2088/731 +f 733/2090/733 732/2089/732 731/2088/731 +f 734/2091/734 732/2089/732 733/2090/733 +f 735/2092/735 734/2091/734 733/2090/733 +f 736/2093/736 734/2091/734 735/2092/735 +f 737/2094/737 736/2093/736 735/2092/735 +f 738/2095/738 736/2093/736 737/2094/737 +f 739/2096/739 738/2095/738 737/2094/737 +f 569/2084/569 580/2097/580 581/2098/581 +f 740/2099/740 580/2097/580 569/2084/569 +f 729/2086/729 740/2099/740 569/2084/569 +f 741/2100/741 740/2099/740 729/2086/729 +f 730/2087/730 741/2100/741 729/2086/729 +f 742/2101/742 741/2100/741 730/2087/730 +f 732/2089/732 742/2101/742 730/2087/730 +f 743/2102/743 742/2101/742 732/2089/732 +f 734/2091/734 743/2102/743 732/2089/732 +f 744/2103/744 743/2102/743 734/2091/734 +f 736/2093/736 744/2103/744 734/2091/734 +f 745/2104/745 744/2103/744 736/2093/736 +f 738/2095/738 745/2104/745 736/2093/736 +f 649/1957/649 746/2105/746 651/1959/651 +f 747/2106/747 746/2105/746 649/1957/649 +f 647/1953/645 747/2106/747 649/1957/649 +f 748/2107/748 747/2106/747 647/1953/645 +f 645/1955/647 748/2107/748 647/1953/645 +f 749/2108/749 748/2107/748 645/1955/647 +f 659/1975/659 749/2108/749 645/1955/647 +f 740/2099/740 749/2108/749 659/1975/659 +f 658/1974/658 740/2099/740 659/1975/659 +f 644/1952/644 740/2099/740 658/1974/658 +f 750/2109/750 591/1777/591 590/1776/590 +f 606/1792/606 591/1777/591 750/2109/750 +f 751/2110/751 606/1792/606 750/2109/750 +f 752/2111/752 606/1792/606 751/2110/751 +f 716/2071/716 752/2111/752 751/2110/751 +f 753/2112/753 752/2111/752 716/2071/716 +f 754/2113/754 753/2112/753 716/2071/716 +f 755/2114/755 753/2112/753 754/2113/754 +f 756/2115/756 755/2114/755 754/2113/754 +f 757/2116/757 714/2067/712 712/2117/714 +f 758/2118/758 714/2067/712 757/2116/757 +f 759/2119/759 758/2118/758 757/2116/757 +f 760/2120/760 758/2118/758 759/2119/759 +f 761/2121/761 760/2120/760 759/2119/759 +f 762/2122/762 760/2120/760 761/2121/761 +f 763/2123/763 762/2122/762 761/2121/761 +f 764/2124/764 762/2122/762 763/2123/763 +f 765/2125/765 743/2102/743 744/2103/744 +f 766/2126/766 743/2102/743 765/2125/765 +f 767/2127/767 766/2126/766 765/2125/765 +f 768/2128/768 766/2126/766 767/2127/767 +f 769/2129/769 768/2128/768 767/2127/767 +f 770/2130/770 768/2128/768 769/2129/769 +f 771/2131/771 770/2130/770 769/2129/769 +f 772/2132/772 770/2130/770 771/2131/771 +f 773/2133/773 744/2103/744 745/2104/745 +f 765/2125/765 744/2103/744 773/2133/773 +f 774/2134/774 765/2125/765 773/2133/773 +f 767/2127/767 765/2125/765 774/2134/774 +f 775/2135/775 767/2127/767 774/2134/774 +f 769/2129/769 767/2127/767 775/2135/775 +f 776/2136/776 769/2129/769 775/2135/775 +f 771/2131/771 769/2129/769 776/2136/776 +f 777/2137/777 771/2138/771 776/2139/776 +f 778/2140/778 771/2138/771 777/2137/777 +f 779/2141/779 778/2140/778 777/2137/777 +f 780/2142/780 778/2140/778 779/2141/779 +f 781/2143/781 780/2142/780 779/2141/779 +f 782/2144/782 780/2142/780 781/2143/781 +f 728/2083/728 782/2144/782 781/2143/781 +f 726/2081/726 782/2144/782 728/2083/728 +f 766/2126/766 742/2101/742 743/2102/743 +f 749/2108/749 742/2101/742 766/2126/766 +f 768/2128/768 749/2108/749 766/2126/766 +f 748/2145/748 749/2108/749 768/2128/768 +f 770/2130/770 748/2145/748 768/2128/768 +f 747/2146/747 748/2145/748 770/2130/770 +f 772/2132/772 747/2146/747 770/2130/770 +f 783/2147/783 747/2146/747 772/2132/772 +f 778/2140/778 772/2148/772 771/2138/771 +f 784/2149/784 772/2148/772 778/2140/778 +f 780/2142/780 784/2149/784 778/2140/778 +f 785/2150/785 784/2149/784 780/2142/780 +f 782/2144/782 785/2150/785 780/2142/780 +f 786/2151/786 785/2150/785 782/2144/782 +f 726/2081/726 786/2151/786 782/2144/782 +f 724/2079/724 786/2151/786 726/2081/726 +f 784/2149/784 783/2152/783 772/2148/772 +f 787/2153/787 783/2152/783 784/2149/784 +f 785/2150/785 787/2153/787 784/2149/784 +f 788/2154/788 787/2153/787 785/2150/785 +f 786/2151/786 788/2154/788 785/2150/785 +f 789/2155/789 788/2154/788 786/2151/786 +f 724/2079/724 789/2155/789 786/2151/786 +f 722/2077/722 789/2155/789 724/2079/724 +f 790/2156/790 763/2157/763 761/2158/761 +f 791/2159/791 763/2157/763 790/2156/790 +f 792/2160/792 791/2159/791 790/2156/790 +f 793/2161/793 791/2159/791 792/2160/792 +f 794/2162/794 793/2161/793 792/2160/792 +f 795/2163/795 793/2161/793 794/2162/794 +f 756/2164/756 795/2163/795 794/2162/794 +f 787/2153/787 663/1981/663 783/2152/783 +f 796/2165/796 663/1981/663 787/2153/787 +f 788/2154/788 796/2165/796 787/2153/787 +f 797/2166/797 796/2165/796 788/2154/788 +f 789/2155/789 797/2166/797 788/2154/788 +f 720/2075/720 797/2166/797 789/2155/789 +f 722/2077/722 720/2075/720 789/2155/789 +f 759/2119/759 790/2156/790 761/2121/761 +f 798/2167/798 790/2156/790 759/2119/759 +f 757/2116/757 798/2167/798 759/2119/759 +f 799/2168/799 798/2167/798 757/2116/757 +f 712/2169/714 799/2168/799 757/2116/757 +f 570/2170/570 799/2168/799 712/2169/714 +f 800/2171/800 716/2071/716 714/2067/712 +f 754/2113/754 716/2071/716 800/2171/800 +f 801/2172/801 754/2113/754 800/2171/800 +f 756/2115/756 754/2113/754 801/2172/801 +f 795/2173/795 756/2115/756 801/2172/801 +f 796/2165/796 662/1980/662 663/1981/663 +f 802/2174/802 662/1980/662 796/2165/796 +f 803/2175/803 802/2174/802 796/2165/796 +f 600/1786/600 802/2174/802 803/2175/803 +f 601/1787/601 600/1786/600 803/2175/803 +f 803/2175/803 590/1776/590 601/1787/601 +f 750/2109/750 590/1776/590 803/2175/803 +f 797/2166/797 750/2109/750 803/2175/803 +f 720/2075/720 750/2109/750 797/2166/797 +f 758/2118/758 800/2171/800 714/2067/712 +f 804/2176/804 800/2171/800 758/2118/758 +f 760/2120/760 804/2176/804 758/2118/758 +f 762/2122/762 804/2176/804 760/2120/760 +s 42 +f 805/2177/805 669/1992/669 671/1994/671 +f 667/1990/667 669/1992/669 805/2177/805 +f 665/1988/665 667/1990/667 805/2177/805 +s 34 +f 619/2178/617 740/2099/740 644/1952/644 +f 580/2097/580 740/2099/740 619/2179/617 +f 617/2180/619 580/2097/580 619/2181/617 +f 783/2152/783 746/2182/746 747/2183/747 +f 651/1973/651 746/2182/746 783/2152/783 +f 663/1981/663 651/1973/651 783/2152/783 +f 802/2174/802 622/1843/622 662/1980/662 +f 625/1849/625 622/1843/622 802/2174/802 +f 600/1786/600 625/1849/625 802/2174/802 +f 751/2110/751 718/2073/718 716/2071/716 +f 720/2075/720 718/2073/718 751/2110/751 +f 750/2109/750 720/2075/720 751/2110/751 +f 798/2167/798 792/2160/792 790/2156/790 +f 794/2162/794 792/2160/792 798/2167/798 +f 799/2168/799 794/2162/794 798/2167/798 +f 806/2184/806 779/2185/779 777/2186/777 +f 781/2187/781 779/2185/779 806/2184/806 +f 728/2188/728 781/2187/781 806/2184/806 +f 806/2184/806 727/2189/727 728/2190/728 +f 739/2191/739 727/2192/727 806/2184/806 +f 738/2193/738 739/2191/739 806/2184/806 +f 806/2184/806 745/2194/745 738/2195/738 +f 773/2196/773 745/2197/745 806/2184/806 +f 774/2198/774 773/2199/773 806/2184/806 +s 44 +f 807/2200/807 703/2058/703 705/2060/705 +f 701/2056/701 703/2058/703 807/2200/807 +f 699/2054/699 701/2056/701 807/2200/807 +s 43 +f 808/2201/808 687/2202/687 689/2203/689 +f 685/2204/685 687/2205/687 808/2206/808 +f 683/2207/683 685/2208/685 808/2209/808 +f 808/2210/808 681/2211/681 683/2212/683 +f 695/2213/695 681/2214/681 808/2215/808 +f 693/2216/693 695/2217/695 808/2218/808 +s 44 +f 807/2200/807 697/2052/697 699/2054/699 +f 711/2066/711 697/2052/697 807/2200/807 +f 709/2064/709 711/2066/711 807/2200/807 +s 34 +f 801/2172/801 762/2122/762 795/2173/795 +f 804/2176/804 762/2122/762 801/2172/801 +f 800/2171/800 804/2176/804 801/2172/801 +s 42 +f 805/2177/805 675/1998/675 677/2000/677 +f 673/1996/673 675/1998/675 805/2177/805 +f 671/1994/671 673/1996/673 805/2177/805 +s 34 +f 791/2159/791 764/2219/764 763/2157/763 +f 793/2161/793 764/2219/764 791/2159/791 +f 756/2164/756 799/2168/799 755/2220/755 +f 794/2162/794 799/2168/799 756/2164/756 +s 44 +f 707/2062/707 807/2200/807 705/2060/705 +f 709/2064/709 807/2200/807 707/2062/707 +s 34 +f 737/2094/737 723/2078/723 725/2080/725 +f 735/2092/735 723/2078/723 737/2094/737 +f 739/2096/739 725/2080/725 727/2082/727 +f 737/2094/737 725/2080/725 739/2096/739 +f 753/2112/753 606/1792/606 752/2111/752 +f 755/2114/755 606/1792/606 753/2112/753 +s 43 +f 691/2221/691 808/2222/808 689/2223/689 +f 693/2224/693 808/2225/808 691/2226/691 +s 34 +f 809/2227/809 762/2122/762 764/2124/764 +f 795/2173/795 762/2122/762 809/2227/809 +f 741/2100/741 749/2108/749 740/2099/740 +f 742/2101/742 749/2108/749 741/2100/741 +f 776/2228/776 806/2184/806 777/2186/777 +f 775/2229/775 806/2184/806 776/2230/776 +f 733/2090/733 719/2074/719 721/2076/721 +f 731/2088/731 719/2074/719 733/2090/733 +f 715/2070/715 731/2088/731 713/2068/713 +f 717/2072/717 731/2088/731 715/2070/715 +f 606/2231/606 799/2168/799 570/2170/570 +f 755/2220/755 799/2168/799 606/2231/606 +s 42 +f 679/2002/679 805/2177/805 677/2000/677 +f 665/1988/665 805/2177/805 679/2002/679 +s 34 +f 735/2092/735 721/2076/721 723/2078/723 +f 733/2090/733 721/2076/721 735/2092/735 +f 764/2219/764 793/2161/793 809/2232/809 +f 717/2072/717 719/2074/719 731/2088/731 +f 795/2163/795 809/2233/809 793/2161/793 +f 796/2165/796 797/2166/797 803/2175/803 +f 775/2234/775 774/2235/774 806/2184/806 +s 46 +f 812/2236/810 811/2237/811 810/2238/812 +f 813/2239/813 811/2240/811 812/2241/810 +f 814/2242/814 813/2243/813 812/2244/810 +f 815/2245/815 813/2246/813 814/2247/814 +f 816/2248/816 815/2249/815 814/2250/814 +f 817/2251/817 815/2252/815 816/2253/816 +f 818/2254/818 817/2255/817 816/2256/816 +f 819/2257/819 817/2258/817 818/2259/818 +f 820/2260/820 819/2261/819 818/2262/818 +f 821/2263/821 819/2264/819 820/2265/820 +f 822/2266/822 821/2267/821 820/2268/820 +f 823/2269/823 821/2270/821 822/2271/822 +f 824/2272/824 823/2273/823 822/2274/822 +f 825/2275/825 823/2276/823 824/2277/824 +f 826/2278/826 825/2279/825 824/2280/824 +f 827/2281/827 825/2282/825 826/2283/826 +f 830/2284/828 829/2285/829 828/2286/830 +f 831/2287/831 829/2288/829 830/2289/828 +f 832/2290/832 831/2291/831 830/2292/828 +f 833/2293/833 831/2294/831 832/2295/832 +f 834/2296/834 833/2297/833 832/2298/832 +f 835/2299/835 833/2300/833 834/2301/834 +f 836/2302/836 835/2303/835 834/2304/834 +f 837/2305/837 835/2306/835 836/2307/836 +f 831/2308/831 838/2309/838 829/2310/829 +f 839/2311/839 838/2312/838 831/2313/831 +f 833/2314/833 839/2315/839 831/2316/831 +f 840/2317/840 839/2318/839 833/2319/833 +f 835/2320/835 840/2321/840 833/2322/833 +f 841/2323/841 840/2324/840 835/2325/835 +f 837/2326/837 841/2327/841 835/2328/835 +f 842/2329/842 841/2330/841 837/2331/837 +f 839/2332/839 810/2333/812 838/2334/838 +f 812/2335/810 810/2336/812 839/2337/839 +f 840/2338/840 812/2339/810 839/2340/839 +f 814/2341/814 812/2342/810 840/2343/840 +f 841/2344/841 814/2345/814 840/2346/840 +f 816/2347/816 814/2348/814 841/2349/841 +f 842/2350/842 816/2351/816 841/2352/841 +f 818/2353/818 816/2354/816 842/2355/842 +f 845/2356/843 844/2357/844 843/2358/845 +f 846/2359/846 844/2360/844 845/2361/843 +f 847/2362/847 846/2363/846 845/2364/843 +f 848/2365/848 846/2366/846 847/2367/847 +f 849/2368/849 848/2369/848 847/2370/847 +f 850/2371/850 848/2372/848 849/2373/849 +f 851/2374/851 850/2375/850 849/2376/849 +f 854/2377/852 853/2378/853 852/2379/854 +f 855/2380/855 853/2381/853 854/2382/852 +f 856/2383/856 855/2384/855 854/2385/852 +f 857/2386/857 855/2387/855 856/2388/856 +f 858/2389/858 857/2390/857 856/2391/856 +f 859/2392/859 857/2393/857 858/2394/858 +f 862/2395/860 861/2396/861 860/2397/862 +f 863/2398/863 861/2399/861 862/2400/860 +f 864/2401/864 863/2402/863 862/2403/860 +f 865/2404/865 863/2405/863 864/2406/864 +f 821/2407/821 865/2408/865 864/2409/864 +f 823/2410/823 865/2411/865 821/2412/821 +f 863/2413/863 866/2414/866 861/2415/861 +f 867/2416/867 866/2417/866 863/2418/863 +f 865/2419/865 867/2420/867 863/2421/863 +f 868/2422/868 867/2423/867 865/2424/865 +f 823/2425/823 868/2426/868 865/2427/865 +f 825/2428/825 868/2429/868 823/2430/823 +f 867/2431/867 869/2432/869 866/2433/866 +f 870/2434/870 869/2435/869 867/2436/867 +f 868/2437/868 870/2438/870 867/2439/867 +f 871/2440/871 870/2441/870 868/2442/868 +f 825/2443/825 871/2444/871 868/2445/868 +f 827/2446/827 871/2447/871 825/2448/825 +f 870/2449/870 852/2450/854 869/2451/869 +f 854/2452/852 852/2453/854 870/2454/870 +f 871/2455/871 854/2456/852 870/2457/870 +f 856/2458/856 854/2459/852 871/2460/871 +f 827/2461/827 856/2462/856 871/2463/871 +f 858/2464/858 856/2465/856 827/2466/827 +f 832/2467/832 859/2468/859 834/2469/834 +f 857/2470/857 859/2471/859 832/2472/832 +f 830/2473/828 857/2474/857 832/2475/832 +f 855/2476/855 857/2477/857 830/2478/828 +f 828/2479/830 855/2480/855 830/2481/828 +f 853/2482/853 855/2483/855 828/2484/830 +f 813/2485/813 872/2486/872 811/2487/811 +f 873/2488/873 872/2489/872 813/2490/813 +f 815/2491/815 873/2492/873 813/2493/813 +f 874/2494/874 873/2495/873 815/2496/815 +f 817/2497/817 874/2498/874 815/2499/815 +f 819/2500/819 874/2501/874 817/2502/817 +f 873/2503/873 860/2504/862 872/2505/872 +f 862/2506/860 860/2507/862 873/2508/873 +f 874/2509/874 862/2510/860 873/2511/873 +f 864/2512/864 862/2513/860 874/2514/874 +f 819/2515/819 864/2516/864 874/2517/874 +f 821/2518/821 864/2519/864 819/2520/819 +f 876/2521/875 843/2522/845 875/2523/876 +f 877/2524/877 843/2525/845 876/2526/875 +f 878/2527/878 877/2528/877 876/2529/875 +f 879/2530/879 877/2531/877 878/2532/878 +f 880/2533/880 879/2534/879 878/2535/878 +f 881/2536/881 879/2537/879 880/2538/880 +f 877/2539/877 845/2540/843 843/2541/845 +f 847/2542/847 845/2543/843 877/2544/877 +f 879/2545/879 847/2546/847 877/2547/877 +f 849/2548/849 847/2549/847 879/2550/879 +f 882/2551/882 849/2552/849 879/2553/879 +f 851/2554/851 849/2555/849 882/2556/882 +f 884/2557/883 851/2558/851 883/2559/884 +f 850/2560/850 851/2561/851 884/2562/883 +f 885/2563/885 850/2564/850 884/2565/883 +f 886/2566/886 850/2567/850 885/2568/885 +f 887/2569/887 876/2570/875 875/2571/876 +f 888/2572/888 876/2570/875 887/2573/887 +f 885/2574/885 888/2575/888 887/2576/887 +f 884/2577/883 888/2578/888 885/2574/885 +f 888/2579/888 878/2580/878 876/2570/875 +f 889/2581/889 878/2580/878 888/2582/888 +f 884/2577/883 889/2583/889 888/2584/888 +f 883/2585/884 889/2586/889 884/2577/883 +f 889/2587/889 880/2588/880 878/2580/878 +f 890/2589/890 880/2588/880 889/2590/889 +f 883/2591/884 890/2592/890 889/2593/889 +f 891/2594/891 890/2595/890 883/2596/884 +f 827/2597/827 893/2598/892 892/2599/893 +f 894/2600/894 893/2601/892 827/2602/827 +f 826/2603/826 894/2604/894 827/2605/827 +f 896/2606/895 844/2607/844 895/2608/896 +f 843/2609/845 844/2610/844 896/2611/895 +f 875/2612/876 843/2613/845 896/2614/895 +f 897/2615/897 829/2616/829 838/2617/838 +f 828/2618/830 829/2619/829 897/2620/897 +f 853/2621/853 828/2622/830 897/2623/897 +f 897/2624/897 852/2625/854 853/2626/853 +f 869/2627/869 852/2628/854 897/2629/897 +f 866/2630/866 869/2631/869 897/2632/897 +f 897/2633/897 861/2634/861 866/2635/866 +f 860/2636/862 861/2637/861 897/2638/897 +f 872/2639/872 860/2640/862 897/2641/897 +f 897/2642/897 811/2643/811 872/2644/872 +f 810/2645/812 811/2646/811 897/2647/897 +f 838/2648/838 810/2649/812 897/2650/897 +f 887/2651/887 895/2652/896 898/2653/898 +f 896/2654/895 895/2655/896 887/2656/887 +f 875/2571/876 896/2657/895 887/2658/887 +f 848/2659/848 898/2660/898 846/2661/846 +f 886/2662/886 898/2663/898 848/2664/848 +f 850/2665/850 886/2666/886 848/2667/848 +f 886/2668/886 887/2669/887 898/2653/898 +f 885/2574/885 887/2670/887 886/2668/886 +f 899/2671/899 879/2672/879 881/2673/881 +f 882/2674/882 879/2675/879 899/2676/899 +f 858/2677/858 892/2678/893 900/2679/900 +f 827/2680/827 892/2681/893 858/2682/858 +f 895/2683/896 846/2684/846 898/2685/898 +f 844/2686/844 846/2687/846 895/2688/896 +f 881/2689/881 890/2690/890 891/2691/891 +f 880/2588/880 890/2692/890 881/2693/881 +f 901/2694/901 834/2695/834 859/2696/859 +f 902/2697/902 834/2698/834 901/2699/901 +f 901/2700/901 903/2701/903 902/2702/902 +f 859/2703/859 903/2704/903 901/2705/901 +f 859/2706/859 900/2707/900 903/2708/903 +f 858/2709/858 900/2710/900 859/2711/859 +f 902/2712/902 836/2713/836 834/2714/834 +f 906/2715/904 905/2716/905 904/2717/906 +f 907/2718/907 905/2719/905 906/2720/904 +f 908/2721/908 907/2722/907 906/2723/904 +f 909/2724/909 907/2725/907 908/2726/908 +f 910/2727/910 909/2728/909 908/2729/908 +f 911/2730/911 909/2731/909 910/2732/910 +f 912/2733/912 911/2734/911 910/2735/910 +f 913/2736/913 911/2737/911 912/2738/912 +f 900/2739/900 913/2740/913 912/2741/912 +f 892/2742/893 913/2743/913 900/2744/900 +f 916/2745/914 915/2746/915 914/2747/916 +f 917/2748/917 915/2749/915 916/2750/914 +f 918/2751/918 917/2752/917 916/2753/914 +f 919/2754/919 917/2755/917 918/2756/918 +f 911/2757/911 919/2758/919 918/2759/918 +f 920/2760/920 919/2761/919 911/2762/911 +f 913/2763/913 920/2764/920 911/2765/911 +f 921/2766/921 920/2767/920 913/2768/913 +f 923/2769/922 915/2770/915 922/2771/923 +f 924/2772/924 915/2773/915 923/2774/922 +f 925/2775/925 924/2776/924 923/2777/922 +f 926/2778/926 924/2779/924 925/2780/925 +f 905/2781/905 926/2782/926 925/2783/925 +f 907/2784/907 926/2785/926 905/2786/905 +f 902/2787/902 908/2788/908 906/2789/904 +f 910/2790/910 908/2791/908 902/2792/902 +f 903/2793/903 910/2794/910 902/2795/902 +f 912/2796/912 910/2797/910 903/2798/903 +f 900/2799/900 912/2800/912 903/2801/903 +f 928/2802/927 904/2803/906 927/2804/928 +f 929/2805/929 904/2806/906 928/2807/927 +f 930/2808/930 929/2809/929 928/2810/927 +f 836/2811/836 929/2812/929 930/2813/930 +f 931/2814/931 923/2815/922 922/2816/923 +f 925/2817/925 923/2818/922 931/2819/931 +f 932/2820/932 925/2821/925 931/2822/931 +f 905/2823/905 925/2824/925 932/2825/932 +f 918/2826/918 909/2827/909 911/2828/911 +f 933/2829/933 909/2830/909 918/2831/918 +f 916/2832/914 933/2833/933 918/2834/918 +f 914/2835/916 933/2836/933 916/2837/914 +f 920/2838/920 932/2839/932 931/2840/931 +f 934/2841/934 932/2842/932 920/2843/920 +f 921/2844/921 934/2845/934 920/2846/920 +f 904/2847/906 935/2848/935 927/2849/928 +f 934/2850/934 935/2851/935 904/2852/906 +f 893/2853/892 913/2854/913 892/2855/893 +f 921/2856/921 913/2857/913 893/2858/892 +f 902/2859/902 929/2860/929 836/2861/836 +f 906/2862/904 929/2863/929 902/2864/902 +f 904/2865/906 932/2866/932 934/2867/934 +f 905/2868/905 932/2869/932 904/2870/906 +f 924/2871/924 914/2872/916 915/2873/915 +f 926/2874/926 914/2875/916 924/2876/924 +f 917/2877/917 922/2878/923 915/2879/915 +f 919/2880/919 922/2881/923 917/2882/917 +f 919/2883/919 931/2884/931 922/2885/923 +f 920/2886/920 931/2887/931 919/2888/919 +f 926/2889/926 933/2890/933 914/2891/916 +f 907/2892/907 933/2893/933 926/2894/926 +f 906/2895/904 904/2896/906 929/2897/929 +f 907/2898/907 909/2899/909 933/2900/933 +s 57 +f 938/2901/936 937/2902/937 936/2903/938 +f 939/2904/939 937/2905/937 938/2906/936 +f 940/2907/940 939/2908/939 938/2909/936 +f 941/2910/941 939/2911/939 940/2912/940 +f 942/2913/942 941/2914/941 940/2915/940 +f 943/2916/943 941/2917/941 942/2918/942 +f 944/2919/944 943/2920/943 942/2921/942 +f 945/2922/945 943/2923/943 944/2924/944 +f 946/2925/946 945/2926/945 944/2927/944 +f 947/2928/947 945/2929/945 946/2930/946 +f 948/2931/948 947/2932/947 946/2933/946 +f 949/2934/949 947/2935/947 948/2936/948 +f 950/2937/950 949/2938/949 948/2939/948 +f 951/2940/951 949/2941/949 950/2942/950 +f 936/2943/938 951/2944/951 950/2945/950 +f 937/2946/937 951/2947/951 936/2948/938 +s 58 +f 954/2949/952 953/2950/953 952/2951/954 +f 955/2952/955 953/2953/953 954/2954/952 +f 956/2955/956 955/2956/955 954/2957/952 +f 957/2958/957 955/2959/955 956/2960/956 +f 958/2961/958 957/2962/957 956/2963/956 +f 959/2964/959 957/2965/957 958/2966/958 +f 960/2967/960 959/2968/959 958/2969/958 +f 961/2970/961 959/2971/959 960/2972/960 +f 962/2973/962 961/2974/961 960/2975/960 +f 963/2976/963 961/2977/961 962/2978/962 +f 964/2979/964 963/2980/963 962/2981/962 +f 965/2982/965 963/2983/963 964/2984/964 +f 966/2985/966 965/2986/965 964/2987/964 +f 967/2988/967 965/2989/965 966/2990/966 +f 952/2991/954 967/2992/967 966/2993/966 +f 953/2994/953 967/2995/967 952/2996/954 +s 59 +f 970/2997/968 969/2998/969 968/2999/970 +f 971/3000/971 969/3001/969 970/3002/968 +f 972/3003/972 971/3004/971 970/3005/968 +f 973/3006/973 971/3007/971 972/3008/972 +f 974/3009/974 973/3010/973 972/3011/972 +f 975/3012/975 973/3013/973 974/3014/974 +f 976/3015/976 975/3016/975 974/3017/974 +f 977/3018/977 975/3019/975 976/3020/976 +f 978/3021/978 977/3022/977 976/3023/976 +f 979/3024/979 977/3025/977 978/3026/978 +f 980/3027/980 979/3028/979 978/3029/978 +f 981/3030/981 979/3031/979 980/3032/980 +f 982/3033/982 981/3034/981 980/3035/980 +f 983/3036/983 981/3037/981 982/3038/982 +f 968/3039/970 983/3040/983 982/3041/982 +f 969/3042/969 983/3043/983 968/3044/970 +s 46 +f 824/3045/824 984/3046/984 826/3047/826 +f 985/3048/985 984/3049/984 824/3050/824 +f 822/3051/822 985/3052/985 824/3053/824 +f 986/3054/986 985/3055/985 822/3056/822 +f 987/3057/987 986/3058/986 822/3059/822 +f 988/3060/988 986/3061/986 987/3062/987 +f 989/3063/989 988/3064/988 987/3065/987 +f 990/3066/990 988/3067/988 989/3068/989 +f 818/3069/818 990/3070/990 989/3071/989 +f 991/3072/991 990/3073/990 818/3074/818 +f 842/3075/842 991/3076/991 818/3077/818 +f 992/3078/992 991/3079/991 842/3080/842 +f 837/3081/837 992/3082/992 842/3083/842 +f 993/3084/993 992/3085/992 837/3086/837 +f 996/3087/994 995/3088/995 994/3089/996 +f 997/3090/997 995/3091/995 996/3092/994 +f 998/3093/998 997/3094/997 996/3095/994 +f 999/3096/999 997/3097/997 998/3098/998 +f 1000/3099/1000 999/3100/999 998/3101/998 +f 1001/3102/1001 999/3103/999 1000/3099/1000 +f 1002/3104/1002 1001/3105/1001 1000/3099/1000 +f 1003/3106/1003 1001/3107/1001 1002/3108/1002 +f 930/3109/930 837/3110/837 836/3111/836 +f 993/3112/993 837/3113/837 930/3114/930 +f 928/3115/927 993/3116/993 930/3117/930 +f 1004/3118/1004 993/3119/993 928/3120/927 +f 1005/3121/1005 1004/3122/1004 928/3123/927 +f 1003/3124/1003 1004/3125/1004 1005/3126/1005 +f 1001/3127/1001 1003/3128/1003 1005/3129/1005 +f 1003/3130/1003 993/3131/993 1004/3132/1004 +f 992/3133/992 993/3134/993 1003/3135/1003 +f 1006/3136/1006 992/3137/992 1003/3138/1003 +f 881/3139/881 992/3140/992 1006/3141/1006 +f 1007/3142/1007 881/3143/881 1006/3144/1006 +f 1008/3145/1008 881/3146/881 1007/3147/1007 +f 1009/3148/1009 1008/3149/1008 1007/3150/1007 +f 997/3151/997 1010/3152/1010 995/3153/995 +f 1011/3154/1011 1010/3155/1010 997/3156/997 +f 999/3157/999 1011/3158/1011 997/3159/997 +f 1012/3160/1012 1011/3161/1011 999/3162/999 +f 1001/3163/1001 1012/3164/1012 999/3165/999 +f 1005/3166/1005 1012/3167/1012 1001/3168/1001 +f 990/3169/990 1013/3170/1013 988/3171/988 +f 883/3172/884 1013/3173/1013 990/3174/990 +f 991/3175/991 883/3176/884 990/3177/990 +f 891/3178/891 883/3179/884 991/3180/991 +f 881/3181/881 891/3182/891 991/3183/991 +f 1000/3099/1000 1014/3184/1014 1002/3185/1002 +f 1015/3186/1015 1014/3184/1014 1000/3099/1000 +f 998/3187/998 1015/3186/1015 1000/3099/1000 +f 1016/3188/1016 1015/3186/1015 998/3189/998 +f 996/3190/994 1016/3191/1016 998/3192/998 +f 1017/3193/1017 986/3194/986 988/3195/988 +f 985/3196/985 986/3197/986 1017/3198/1017 +f 1018/3199/1018 985/3200/985 1017/3201/1017 +f 984/3202/984 985/3203/985 1018/3204/1018 +f 882/3205/882 1018/3206/1018 851/3207/851 +f 984/3208/984 1018/3209/1018 882/3210/882 +f 894/3211/894 984/3212/984 882/3213/882 +f 826/3214/826 984/3215/984 894/3216/894 +f 1020/3217/1019 1019/3218/1020 1014/3219/1014 +f 1021/3220/1021 1019/3221/1020 1020/3217/1019 +f 1022/3222/1022 1021/3220/1021 1020/3217/1019 +f 1023/3223/1023 1021/3220/1021 1022/3222/1022 +f 1026/3224/1024 1025/3225/1025 1024/3226/1026 +f 1027/3227/1027 1025/3228/1025 1026/3229/1024 +f 899/3230/899 1027/3231/1027 1026/3232/1024 +f 1028/3233/1028 1027/3234/1027 899/3235/899 +f 1024/3236/1026 1029/3237/1029 935/3238/935 +f 1019/3239/1020 1029/3240/1029 1024/3241/1026 +f 1002/3242/1002 1019/3243/1020 1024/3244/1026 +f 1014/3219/1014 1019/3245/1020 1002/3246/1002 +s 57 +f 1030/3247/1030 945/3248/945 947/3249/947 +f 943/3250/943 945/3251/945 1030/3252/1030 +f 941/3253/941 943/3254/943 1030/3255/1030 +s 46 +f 894/3256/894 921/3257/921 893/3258/892 +f 934/3259/934 921/3260/921 894/3261/894 +f 935/3262/935 934/3263/934 894/3264/894 +f 1026/3265/1024 882/3266/882 899/3267/899 +f 894/3268/894 882/3269/882 1026/3270/1024 +f 935/3271/935 894/3272/894 1026/3273/1024 +f 1011/3274/1011 1029/3275/1029 1010/3276/1010 +f 935/3277/935 1029/3278/1029 1011/3279/1011 +f 927/3280/928 935/3281/935 1011/3282/1011 +f 1032/3283/1031 994/3089/996 1031/3284/1032 +f 996/3285/994 994/3089/996 1032/3286/1031 +f 1016/3287/1016 996/3288/994 1032/3289/1031 +f 1021/3220/1021 1029/3290/1029 1019/3291/1020 +f 1010/3292/1010 1029/3293/1029 1021/3220/1021 +f 1023/3223/1023 1010/3292/1010 1021/3220/1021 +s 59 +f 1033/3294/1033 977/3295/977 979/3296/979 +f 975/3297/975 977/3298/977 1033/3299/1033 +f 973/3300/973 975/3301/975 1033/3302/1033 +s 58 +f 1034/3303/1034 961/3304/961 963/3305/963 +f 959/3306/959 961/3307/961 1034/3308/1034 +f 957/3309/957 959/3310/959 1034/3311/1034 +s 46 +f 1031/3312/1032 1023/3223/1023 1022/3313/1022 +f 994/3314/996 1023/3223/1023 1031/3315/1032 +f 1022/3316/1022 1015/3186/1015 1031/3317/1032 +f 1020/3318/1019 1015/3186/1015 1022/3316/1022 +f 1011/3319/1011 928/3320/927 927/3321/928 +f 1012/3322/1012 928/3323/927 1011/3324/1011 +f 1035/3325/1035 899/3326/899 881/3327/881 +f 1028/3328/1028 899/3329/899 1035/3330/1035 +f 989/3331/989 820/3332/820 818/3333/818 +f 987/3334/987 820/3335/820 989/3336/989 +s 59 +f 981/3337/981 1033/3338/1033 979/3339/979 +f 983/3340/983 1033/3341/1033 981/3342/981 +f 969/3343/969 1033/3344/1033 983/3345/983 +f 971/3346/971 1033/3347/1033 969/3348/969 +s 46 +f 1003/3349/1003 1007/3350/1007 1006/3351/1006 +f 1009/3352/1009 1007/3353/1007 1003/3354/1003 +f 1032/3355/1031 1015/3186/1015 1016/3356/1016 +f 1031/3317/1032 1015/3186/1015 1032/3355/1031 +s 58 +f 965/3357/965 1034/3358/1034 963/3359/963 +f 967/3360/967 1034/3361/1034 965/3362/965 +f 953/3363/953 1034/3364/1034 967/3365/967 +f 955/3366/955 1034/3367/1034 953/3368/953 +s 46 +f 995/3369/995 1023/3223/1023 994/3370/996 +f 1010/3292/1010 1023/3223/1023 995/3369/995 +f 1003/3371/1003 1025/3372/1025 1009/3373/1009 +f 1024/3374/1026 1025/3375/1025 1003/3376/1003 +s 57 +f 949/3377/949 1030/3378/1030 947/3379/947 +f 951/3380/951 1030/3381/1030 949/3382/949 +f 937/3383/937 1030/3384/1030 951/3385/951 +f 939/3386/939 1030/3387/1030 937/3388/937 +s 46 +f 1026/3389/1024 1024/3390/1026 935/3391/935 +f 1035/3392/1035 881/3393/881 1008/3394/1008 +f 1020/3318/1019 1014/3184/1014 1015/3186/1015 +f 991/3395/991 992/3396/992 881/3397/881 +f 822/3398/822 820/3399/820 987/3400/987 +f 1024/3401/1026 1003/3402/1003 1002/3403/1002 +f 1005/3404/1005 928/3405/927 1012/3406/1012 +s 59 +f 971/3407/971 973/3408/973 1033/3409/1033 +s 58 +f 955/3410/955 957/3411/957 1034/3412/1034 +s 57 +f 939/3413/939 941/3414/941 1030/3415/1030 +s 34 +f 1038/3416/1036 1037/3417/1037 1036/3418/1038 +f 1039/3419/1039 1037/3420/1037 1038/3421/1036 +f 1040/3422/1040 1039/3423/1039 1038/3424/1036 +f 1041/3425/1041 1039/3426/1039 1040/3427/1040 +f 1042/3428/1042 1041/3429/1041 1040/3430/1040 +f 620/3431/620 1041/3432/1041 1042/3433/1042 +f 618/3434/618 620/3435/620 1042/3436/1042 +s 46 +f 1025/3437/1025 1043/3438/1043 1009/3439/1009 +f 1044/3440/1044 1043/3441/1043 1025/3442/1025 +f 1045/3443/1045 1044/3444/1044 1025/3445/1025 +f 1046/3446/1046 1044/3447/1044 1045/3448/1045 +f 1047/3449/1047 1046/3450/1046 1045/3451/1045 +f 1048/3452/1048 1046/3453/1046 1047/3454/1047 +f 1049/3455/1049 1048/3456/1048 1047/3457/1047 +f 1043/3458/1043 1008/3459/1008 1009/3460/1009 +f 1050/3461/1050 1008/3462/1008 1043/3463/1043 +f 1051/3464/1051 1050/3465/1050 1043/3466/1043 +f 1052/3467/1052 1050/3468/1050 1051/3469/1051 +f 1053/3470/1053 1052/3471/1052 1051/3472/1051 +f 1054/3473/1054 1052/3474/1052 1053/3475/1053 +s 34 +f 627/1888/627 1055/3476/1055 626/1886/626 +f 1056/3477/1056 1055/3478/1055 627/1888/627 +f 1057/3479/1057 1056/3480/1056 627/1888/627 +f 1058/3481/1058 1056/3482/1056 1057/3483/1057 +f 1059/3484/1059 1058/3485/1058 1057/3486/1057 +f 1062/3487/1060 1061/3488/1061 1060/3489/1062 +f 1063/3490/1063 1061/3491/1061 1062/3492/1060 +f 1064/3493/1064 1063/3494/1063 1062/3495/1060 +f 628/1890/628 1063/3496/1063 1064/3497/1064 +f 623/1846/623 628/1890/628 1064/3498/1064 +f 1064/3499/1064 620/3500/620 623/1846/623 +f 1041/3501/1041 620/3502/620 1064/3503/1064 +f 1062/3504/1060 1041/3505/1041 1064/3506/1064 +f 1039/3507/1039 1041/3508/1041 1062/3509/1060 +f 1060/3510/1062 1039/3511/1039 1062/3512/1060 +s 46 +f 1065/3513/1065 1046/3514/1046 1048/3515/1048 +f 1044/3516/1044 1046/3517/1046 1065/3518/1065 +f 1051/3519/1051 1044/3520/1044 1065/3521/1065 +f 1043/3522/1043 1044/3523/1044 1051/3524/1051 +f 1027/3525/1027 1045/3526/1045 1025/3527/1025 +f 1066/3528/1066 1045/3529/1045 1027/3530/1027 +f 1028/3531/1028 1066/3532/1066 1027/3533/1027 +f 1067/3534/1067 1066/3535/1066 1028/3536/1028 +s 34 +f 1059/3537/1059 1036/3538/1038 1058/3539/1058 +f 1038/3540/1036 1036/3541/1038 1059/3542/1059 +f 1040/3543/1040 1038/3544/1036 1059/3545/1059 +s 46 +f 1054/3546/1054 1048/3547/1048 1049/3548/1049 +f 1065/3549/1065 1048/3550/1048 1054/3551/1054 +f 1053/3552/1053 1065/3553/1065 1054/3554/1054 +f 1050/3555/1050 1035/3556/1035 1008/3557/1008 +f 1068/3558/1068 1035/3559/1035 1050/3560/1050 +f 1052/3561/1052 1068/3562/1068 1050/3563/1050 +f 1066/3564/1066 1047/3565/1047 1045/3566/1045 +f 1069/3567/1069 1047/3568/1047 1066/3569/1066 +f 1067/3570/1067 1069/3571/1069 1066/3572/1066 +s 34 +f 1061/3573/1061 1058/3574/1058 1036/3575/1038 +f 1056/3576/1056 1058/3577/1058 1061/3578/1061 +f 1055/3579/1055 1056/3580/1056 1061/3581/1061 +s 46 +f 1068/3582/1068 1028/3583/1028 1035/3584/1035 +f 1067/3585/1067 1028/3586/1028 1068/3587/1068 +f 1049/3588/1049 1052/3589/1052 1054/3590/1054 +f 1069/3591/1069 1052/3592/1052 1049/3593/1049 +f 1067/3594/1067 1052/3595/1052 1069/3596/1069 +f 1068/3597/1068 1052/3598/1052 1067/3599/1067 +s 34 +f 618/3600/618 1057/3601/1057 627/1888/627 +f 1042/3602/1042 1057/3603/1057 618/3604/618 +f 1042/3605/1042 1059/3606/1059 1057/3607/1057 +f 1040/3608/1040 1059/3609/1059 1042/3610/1042 +f 1037/3611/1037 1061/3612/1061 1036/3613/1038 +f 1060/3614/1062 1061/3615/1061 1037/3616/1037 +f 626/1891/626 1063/3617/1063 628/1890/628 +f 1055/3618/1055 1063/3619/1063 626/1891/626 +f 1037/3620/1037 1039/3621/1039 1060/3622/1062 +s 46 +f 1047/3623/1047 1069/3624/1069 1049/3625/1049 +f 1065/3626/1065 1053/3627/1053 1051/3628/1051 +s 34 +f 1061/3629/1061 1063/3630/1063 1055/3631/1055 +s 46 +f 1017/3632/1017 1070/3633/1070 1018/3634/1018 +f 1071/3635/1071 1070/3636/1070 1017/3637/1017 +f 1072/3638/1072 1071/3639/1071 1017/3640/1017 +f 1073/3641/1073 1071/3642/1071 1072/3643/1072 +f 1074/3644/1074 1073/3645/1073 1072/3646/1072 +f 1075/3647/1075 1073/3648/1073 1074/3649/1074 +f 1076/3650/1076 1075/3651/1075 1074/3652/1074 +f 1077/3653/1077 1075/3654/1075 1076/3650/1076 +f 1076/3655/1076 1078/3656/1078 1077/3657/1077 +f 1079/3658/1079 1078/3659/1078 1076/3660/1076 +f 1080/3661/1080 1079/3662/1079 1076/3663/1076 +f 1081/3664/1081 1079/3665/1079 1080/3666/1080 +f 1082/3667/1082 1081/3668/1081 1080/3669/1080 +f 883/3670/884 1081/3671/1081 1082/3672/1082 +f 1085/3673/1083 1084/3674/1084 1083/3675/1085 +f 1086/3676/1086 1084/3677/1084 1085/3678/1083 +f 1087/3679/1087 1086/3680/1086 1085/3681/1083 +f 1078/3682/1078 1086/3683/1086 1087/3684/1087 +f 1077/3685/1077 1078/3686/1078 1087/3687/1087 +f 1083/3688/1085 1075/3689/1075 1085/3690/1083 +f 1088/3691/1088 1075/3692/1075 1083/3693/1085 +f 1089/3694/1089 1088/3695/1088 1083/3696/1085 +f 1071/3697/1071 1088/3698/1088 1089/3699/1089 +f 1070/3700/1070 1071/3701/1071 1089/3702/1089 +f 988/3703/988 1072/3704/1072 1017/3705/1017 +f 1090/3706/1090 1072/3707/1072 988/3708/988 +f 1091/3709/1091 1090/3710/1090 988/3711/988 +f 1082/3712/1082 1090/3713/1090 1091/3714/1091 +f 883/3715/884 1082/3712/1082 1091/3716/1091 +f 1070/3717/1070 1081/3718/1081 1018/3719/1018 +f 1092/3720/1092 1081/3721/1081 1070/3722/1070 +f 1089/3723/1089 1092/3724/1092 1070/3725/1070 +f 1084/3726/1084 1092/3727/1092 1089/3728/1089 +f 1083/3729/1085 1084/3730/1084 1089/3731/1089 +f 1092/3732/1092 1079/3733/1079 1081/3734/1081 +f 1093/3735/1093 1079/3736/1079 1092/3737/1092 +f 1084/3738/1084 1093/3739/1093 1092/3740/1092 +f 1086/3741/1086 1093/3742/1093 1084/3743/1084 +f 1080/3744/1080 1090/3745/1090 1082/3712/1082 +f 1074/3746/1074 1090/3747/1090 1080/3744/1080 +f 1076/3650/1076 1074/3748/1074 1080/3744/1080 +f 1087/3749/1087 1075/3750/1075 1077/3653/1077 +f 1085/3751/1083 1075/3752/1075 1087/3753/1087 +f 1091/3754/1091 1013/3755/1013 883/3756/884 +f 988/3757/988 1013/3758/1013 1091/3759/1091 +f 851/3760/851 1081/3761/1081 883/3762/884 +f 1018/3763/1018 1081/3764/1081 851/3765/851 +f 1078/3766/1078 1093/3767/1093 1086/3768/1086 +f 1079/3769/1079 1093/3770/1093 1078/3771/1078 +f 1088/3772/1088 1073/3773/1073 1075/3774/1075 +f 1071/3775/1071 1073/3776/1073 1088/3777/1088 +f 1090/3778/1090 1074/3779/1074 1072/3780/1072 +s 67 +f 1096/3781/1094 1095/3782/1095 1094/3783/1096 +f 1097/3784/1097 1095/3782/1095 1096/3781/1094 +f 1098/3785/1098 1097/3784/1097 1096/3781/1094 +f 1099/3786/1099 1097/3784/1097 1098/3785/1098 +f 1100/3787/1100 1099/3786/1099 1098/3785/1098 +f 1101/3788/1101 1099/3786/1099 1100/3787/1100 +f 1102/3789/1102 1101/3788/1101 1100/3787/1100 +f 1103/3790/1103 1101/3788/1101 1102/3789/1102 +f 1104/3791/1104 1103/3790/1103 1102/3789/1102 +f 1105/3792/1105 1103/3790/1103 1104/3791/1104 +f 1106/3793/1106 1105/3792/1105 1104/3791/1104 +f 1107/3794/1107 1105/3792/1105 1106/3793/1106 +f 1108/3795/1108 1107/3794/1107 1106/3793/1106 +f 1109/3796/1109 1107/3794/1107 1108/3795/1108 +f 1110/3797/1110 1109/3796/1109 1108/3795/1108 +f 1111/3798/1111 1109/3796/1109 1110/3797/1110 +f 1112/3799/1112 1111/3798/1111 1110/3797/1110 +f 1113/3800/1113 1111/3798/1111 1112/3799/1112 +f 1114/3801/1114 1113/3800/1113 1112/3799/1112 +f 1115/3802/1115 1113/3800/1113 1114/3801/1114 +f 1116/3803/1116 1115/3802/1115 1114/3801/1114 +f 1117/3804/1117 1115/3802/1115 1116/3803/1116 +s 68 +f 1120/3805/1118 1119/3806/1119 1118/3807/1120 +f 1121/3808/1121 1119/3806/1119 1120/3805/1118 +f 1122/3809/1122 1121/3808/1121 1120/3805/1118 +f 1123/3810/1123 1121/3808/1121 1122/3809/1122 +f 1124/3811/1124 1123/3810/1123 1122/3809/1122 +f 1125/3812/1125 1123/3810/1123 1124/3811/1124 +f 1126/3813/1126 1125/3812/1125 1124/3811/1124 +f 1127/3814/1127 1125/3812/1125 1126/3813/1126 +f 1128/3815/1128 1127/3814/1127 1126/3813/1126 +f 1129/3816/1129 1127/3814/1127 1128/3815/1128 +f 1130/3817/1130 1129/3816/1129 1128/3815/1128 +f 1131/3818/1131 1129/3816/1129 1130/3817/1130 +f 1132/3819/1132 1131/3818/1131 1130/3817/1130 +f 1133/3820/1133 1131/3818/1131 1132/3819/1132 +f 1134/3821/1134 1133/3820/1133 1132/3819/1132 +f 1135/3822/1135 1133/3820/1133 1134/3821/1134 +f 1136/3823/1136 1135/3822/1135 1134/3821/1134 +f 1137/3824/1137 1135/3822/1135 1136/3823/1136 +f 1138/3825/1138 1137/3824/1137 1136/3823/1136 +f 1139/3826/1139 1137/3824/1137 1138/3825/1138 +f 1140/3827/1140 1139/3826/1139 1138/3825/1138 +f 1141/3828/1141 1139/3826/1139 1140/3827/1140 +f 1144/3829/1142 1143/3830/1143 1142/3831/1144 +f 1145/3832/1145 1143/3830/1143 1144/3829/1142 +f 1146/3833/1146 1145/3832/1145 1144/3829/1142 +f 1147/3834/1147 1145/3832/1145 1146/3835/1146 +f 1148/3836/1148 1147/3837/1147 1146/3838/1146 +f 1149/3839/1149 1147/3840/1147 1148/3836/1148 +f 1118/3807/1120 1149/3839/1149 1148/3836/1148 +f 1150/3841/1150 1149/3839/1149 1118/3807/1120 +f 1119/3806/1119 1150/3841/1150 1118/3807/1120 +f 1151/3842/1151 1150/3841/1150 1119/3806/1119 +f 1152/3843/1152 1151/3842/1151 1119/3806/1119 +f 1153/3844/1153 1151/3842/1151 1152/3843/1152 +f 1141/3845/1141 1153/3844/1153 1152/3843/1152 +f 1154/3846/1154 1153/3844/1153 1141/3847/1141 +f 1140/3827/1140 1154/3848/1154 1141/3849/1141 +f 1155/3850/1155 1154/3851/1154 1140/3827/1140 +f 1156/3852/1156 1155/3850/1155 1140/3827/1140 +f 1157/3853/1157 1155/3850/1155 1156/3852/1156 +f 1158/3854/1158 1157/3853/1157 1156/3852/1156 +s 70 +f 1116/3855/1159 1094/3856/1160 1117/3857/1161 +f 1096/3858/1162 1094/3856/1160 1116/3855/1159 +f 1114/3859/1163 1096/3858/1162 1116/3855/1159 +f 1098/3860/1164 1096/3858/1162 1114/3859/1163 +f 1112/3861/1165 1098/3860/1164 1114/3859/1163 +f 1100/3862/1166 1098/3860/1164 1112/3861/1165 +f 1110/3863/1167 1100/3862/1166 1112/3861/1165 +f 1102/3864/1168 1100/3862/1166 1110/3863/1167 +f 1108/3865/1169 1102/3864/1168 1110/3863/1167 +s 68 +f 1143/3830/1143 1101/3788/1170 1103/3790/1171 +f 1159/3866/1172 1101/3788/1170 1143/3830/1143 +f 1160/3867/1173 1159/3866/1172 1143/3830/1143 +f 1161/3868/1174 1159/3866/1172 1160/3869/1173 +f 1162/3870/1175 1161/3868/1174 1160/3871/1173 +f 1163/3872/1176 1161/3868/1174 1162/3870/1175 +f 1164/3873/1177 1163/3872/1176 1162/3870/1175 +f 1095/3782/1178 1163/3872/1176 1164/3873/1177 +f 1094/3783/1179 1095/3782/1178 1164/3873/1177 +f 1134/3821/1134 1165/3874/1180 1136/3823/1136 +f 1166/3875/1181 1165/3874/1180 1134/3821/1134 +f 1132/3819/1132 1166/3875/1181 1134/3821/1134 +f 1167/3876/1182 1166/3875/1181 1132/3819/1132 +f 1130/3817/1130 1167/3876/1182 1132/3819/1132 +f 1168/3877/1183 1167/3876/1182 1130/3817/1130 +f 1169/3878/1184 1168/3877/1183 1130/3817/1130 +f 1107/3794/1185 1168/3877/1183 1169/3878/1184 +f 1105/3792/1186 1107/3794/1185 1169/3878/1184 +f 1170/3879/1187 1155/3850/1155 1157/3853/1157 +f 1171/3880/1188 1155/3850/1155 1170/3879/1187 +f 1172/3881/1189 1171/3882/1188 1170/3879/1187 +f 1173/3883/1190 1171/3884/1188 1172/3885/1189 +f 1174/3886/1191 1173/3883/1190 1172/3887/1189 +f 1175/3888/1192 1173/3883/1190 1174/3886/1191 +f 1176/3889/1193 1175/3888/1192 1174/3886/1191 +f 1094/3783/1179 1175/3888/1192 1176/3889/1193 +f 1138/3825/1138 1156/3852/1156 1140/3827/1140 +f 1177/3890/1194 1156/3852/1156 1138/3825/1138 +f 1136/3823/1136 1177/3890/1194 1138/3825/1138 +f 1178/3891/1195 1177/3890/1194 1136/3823/1136 +f 1165/3874/1180 1178/3891/1195 1136/3823/1136 +f 1117/3804/1196 1178/3891/1195 1165/3874/1180 +f 1115/3802/1197 1117/3804/1196 1165/3874/1180 +s 72 +f 1180/3892/1198 1158/3854/1199 1179/3893/1200 +f 1157/3853/1201 1158/3854/1199 1180/3892/1198 +f 1181/3894/1202 1157/3853/1201 1180/3892/1198 +f 1170/3879/1203 1157/3853/1201 1181/3894/1202 +f 1182/3895/1204 1170/3879/1203 1181/3894/1202 +f 1172/3896/1205 1170/3879/1203 1182/3895/1204 +f 1183/3897/1206 1172/3898/1205 1182/3895/1204 +s 68 +f 1184/3899/1207 1135/3822/1135 1137/3824/1137 +f 1185/3900/1208 1135/3822/1135 1184/3899/1207 +f 1121/3808/1121 1185/3900/1208 1184/3899/1207 +f 1186/3901/1209 1185/3900/1208 1121/3808/1121 +f 1123/3810/1123 1186/3901/1209 1121/3808/1121 +f 1125/3812/1125 1186/3901/1209 1123/3810/1123 +f 1188/3902/1210 1151/3842/1151 1187/3903/1211 +f 1189/3904/1212 1151/3842/1151 1188/3902/1210 +f 1190/3905/1213 1189/3904/1212 1188/3902/1210 +f 1191/3906/1214 1189/3904/1212 1190/3905/1213 +f 1162/3870/1175 1191/3906/1214 1190/3905/1213 +f 1160/3907/1173 1191/3906/1214 1162/3870/1175 +f 1169/3878/1184 1142/3908/1144 1105/3792/1186 +f 1144/3829/1142 1142/3909/1144 1169/3878/1184 +f 1192/3910/1215 1144/3829/1142 1169/3878/1184 +f 1193/3911/1216 1144/3829/1142 1192/3912/1215 +f 1128/3815/1128 1193/3911/1216 1192/3913/1215 +f 1126/3813/1126 1193/3911/1216 1128/3815/1128 +f 1175/3888/1192 1187/3903/1211 1173/3883/1190 +f 1188/3902/1210 1187/3903/1211 1175/3888/1192 +f 1194/3914/1217 1188/3902/1210 1175/3888/1192 +f 1190/3905/1213 1188/3902/1210 1194/3914/1217 +f 1164/3873/1177 1190/3905/1213 1194/3914/1217 +f 1162/3870/1175 1190/3905/1213 1164/3873/1177 +f 1097/3784/1218 1163/3872/1176 1095/3782/1178 +f 1161/3868/1174 1163/3872/1176 1097/3784/1218 +f 1099/3786/1219 1161/3868/1174 1097/3784/1218 +f 1159/3866/1172 1161/3868/1174 1099/3786/1219 +f 1101/3788/1170 1159/3866/1172 1099/3786/1219 +s 74 +f 1197/3915/1220 1196/3916/1221 1195/3917/1222 +f 1179/3918/1223 1196/3916/1221 1197/3915/1220 +f 1198/3919/1224 1179/3918/1223 1197/3915/1220 +f 1180/3920/1225 1179/3918/1223 1198/3919/1224 +f 1183/3921/1226 1180/3920/1225 1198/3919/1224 +s 68 +f 1121/3808/1121 1152/3843/1152 1119/3806/1119 +f 1199/3922/1227 1152/3843/1152 1121/3808/1121 +f 1184/3899/1207 1199/3922/1227 1121/3808/1121 +f 1139/3826/1139 1199/3922/1227 1184/3899/1207 +f 1137/3824/1137 1139/3826/1139 1184/3899/1207 +f 1200/3923/1228 1178/3891/1195 1117/3804/1196 +f 1177/3890/1194 1178/3891/1195 1200/3923/1228 +f 1158/3854/1158 1177/3890/1194 1200/3923/1228 +f 1156/3852/1156 1177/3890/1194 1158/3854/1158 +f 1148/3836/1148 1126/3813/1126 1118/3807/1120 +f 1193/3911/1216 1126/3813/1126 1148/3836/1148 +f 1146/3924/1146 1193/3911/1216 1148/3836/1148 +f 1144/3829/1142 1193/3911/1216 1146/3925/1146 +f 1185/3900/1208 1133/3820/1133 1135/3822/1135 +f 1201/3926/1229 1133/3820/1133 1185/3900/1208 +f 1186/3901/1209 1201/3926/1229 1185/3900/1208 +f 1125/3812/1125 1201/3926/1229 1186/3901/1209 +f 1201/3926/1229 1131/3818/1131 1133/3820/1133 +f 1202/3927/1230 1131/3818/1131 1201/3926/1229 +f 1125/3812/1125 1202/3927/1230 1201/3926/1229 +f 1127/3814/1127 1202/3927/1230 1125/3812/1125 +s 72 +f 1179/3893/1200 1117/3804/1231 1196/3928/1232 +f 1200/3923/1233 1117/3804/1231 1179/3893/1200 +f 1158/3854/1199 1200/3923/1233 1179/3893/1200 +s 68 +f 1118/3807/1120 1122/3809/1122 1120/3805/1118 +f 1124/3811/1124 1122/3809/1122 1118/3807/1120 +f 1126/3813/1126 1124/3811/1124 1118/3807/1120 +f 1187/3903/1211 1154/3929/1154 1173/3883/1190 +f 1153/3844/1153 1154/3930/1154 1187/3903/1211 +f 1151/3842/1151 1153/3844/1153 1187/3903/1211 +f 1150/3841/1150 1191/3906/1214 1149/3839/1149 +f 1189/3904/1212 1191/3906/1214 1150/3841/1150 +f 1151/3842/1151 1189/3904/1212 1150/3841/1150 +s 72 +f 1094/3783/1234 1197/3931/1235 1195/3932/1236 +f 1176/3889/1237 1197/3931/1235 1094/3783/1234 +s 70 +f 1104/3933/1238 1108/3865/1169 1106/3934/1239 +f 1102/3864/1168 1108/3865/1169 1104/3933/1238 +s 72 +f 1176/3889/1237 1198/3935/1240 1197/3931/1235 +f 1174/3886/1241 1198/3935/1240 1176/3889/1237 +f 1174/3886/1241 1183/3897/1206 1198/3935/1240 +f 1172/3936/1205 1183/3897/1206 1174/3886/1241 +s 68 +f 1141/3937/1141 1199/3922/1227 1139/3826/1139 +f 1152/3843/1152 1199/3922/1227 1141/3938/1141 +f 1103/3790/1171 1142/3939/1144 1143/3940/1143 +f 1105/3792/1186 1142/3941/1144 1103/3790/1171 +f 1129/3816/1129 1202/3927/1230 1127/3814/1127 +f 1131/3818/1131 1202/3927/1230 1129/3816/1129 +f 1145/3832/1145 1160/3942/1173 1143/3830/1143 +f 1147/3943/1147 1160/3944/1173 1145/3832/1145 +f 1165/3874/1180 1113/3800/1242 1115/3802/1197 +f 1166/3875/1181 1113/3800/1242 1165/3874/1180 +f 1171/3945/1188 1154/3946/1154 1155/3850/1155 +f 1173/3883/1190 1154/3947/1154 1171/3948/1188 +s 74 +f 1181/3949/1243 1183/3921/1226 1182/3950/1244 +f 1180/3920/1225 1183/3921/1226 1181/3949/1243 +s 68 +f 1130/3817/1130 1192/3951/1215 1169/3878/1184 +f 1128/3815/1128 1192/3952/1215 1130/3817/1130 +f 1167/3876/1182 1109/3796/1245 1111/3798/1246 +f 1168/3877/1183 1109/3796/1245 1167/3876/1182 +f 1166/3875/1181 1111/3798/1246 1113/3800/1242 +f 1167/3876/1182 1111/3798/1246 1166/3875/1181 +f 1094/3783/1179 1194/3914/1217 1175/3888/1192 +f 1164/3873/1177 1194/3914/1217 1094/3783/1179 +s 77 +f 1195/3917/1247 1117/3857/1248 1094/3856/1249 +f 1196/3916/1250 1117/3857/1248 1195/3917/1247 +s 68 +f 1147/3953/1147 1191/3906/1214 1160/3954/1173 +f 1149/3839/1149 1191/3906/1214 1147/3955/1147 +f 1109/3796/1245 1168/3877/1183 1107/3794/1185 +s 78 +f 1205/3956/1251 1204/3957/1252 1203/3958/1253 +f 1206/3959/1254 1204/3957/1252 1205/3956/1251 +f 1207/3960/1255 1206/3959/1254 1205/3956/1251 +f 1208/3961/1256 1206/3959/1254 1207/3960/1255 +f 1209/3962/1257 1208/3961/1256 1207/3960/1255 +f 1207/3960/1255 1210/3963/1258 1209/3962/1257 +f 1211/3964/1259 1210/3963/1258 1207/3960/1255 +f 1212/3965/1260 1211/3964/1259 1207/3960/1255 +f 1213/3966/1261 1211/3964/1259 1212/3967/1260 +f 1207/3960/1255 1214/3968/1262 1212/3969/1260 +f 1215/3970/1263 1214/3971/1262 1207/3960/1255 +f 1216/3972/1264 1215/3973/1263 1207/3960/1255 +f 1217/3974/1265 1205/3956/1251 1203/3958/1253 +f 1216/3975/1264 1205/3956/1251 1217/3976/1265 +f 1218/3977/1266 1211/3964/1259 1213/3966/1261 +f 1219/3978/1267 1211/3964/1259 1218/3977/1266 +f 1210/3963/1258 1211/3964/1259 1219/3979/1267 +f 1205/3956/1251 1216/3980/1264 1207/3960/1255 +f 1220/3981/1268 1216/3982/1264 1217/3983/1265 +f 1215/3984/1263 1216/3985/1264 1220/3981/1268 +f 1221/3986/1269 1215/3987/1263 1220/3981/1268 +f 1214/3988/1262 1215/3989/1263 1221/3986/1269 +f 1222/3990/1270 1214/3991/1262 1221/3986/1269 +f 1223/3992/1271 1214/3993/1262 1222/3990/1270 +f 1224/3994/1272 1223/3992/1271 1222/3990/1270 +f 1213/3966/1261 1223/3992/1271 1224/3994/1272 +s 79 +f 1219/3995/1273 1226/3996/1274 1225/3997/1275 +f 1227/3998/1276 1226/3996/1274 1219/3999/1273 +f 1218/3977/1277 1227/3998/1276 1219/4000/1273 +f 1228/4001/1278 1227/3998/1276 1218/3977/1277 +f 1203/3958/1279 1228/4001/1278 1218/3977/1277 +s 78 +f 1229/4002/1280 1226/3996/1281 1227/3998/1282 +f 1230/4003/1283 1226/3996/1281 1229/4002/1280 +f 1231/4004/1284 1230/4005/1283 1229/4002/1280 +f 1209/3962/1257 1230/4006/1283 1231/4007/1284 +f 1230/4008/1283 1225/4009/1285 1226/3996/1281 +f 1232/4010/1286 1225/4011/1285 1230/4012/1283 +f 1209/3962/1257 1232/4013/1286 1230/4014/1283 +f 1210/3963/1258 1232/4015/1286 1209/3962/1257 +f 1233/4016/1287 1222/3990/1270 1221/3986/1269 +f 1234/4017/1288 1222/3990/1270 1233/4018/1287 +f 1235/4019/1289 1234/4020/1288 1233/4021/1287 +s 79 +f 1218/3977/1277 1236/4022/1290 1203/3958/1279 +f 1235/4023/1291 1236/4024/1290 1218/3977/1277 +f 1213/3966/1292 1235/4025/1291 1218/3977/1277 +s 78 +f 1206/3959/1254 1237/4026/1293 1204/3957/1252 +f 1208/3961/1256 1237/4027/1293 1206/3959/1254 +f 1223/3992/1271 1212/4028/1260 1214/4029/1262 +f 1213/3966/1261 1212/4030/1260 1223/3992/1271 +s 79 +f 1234/4031/1294 1213/3966/1292 1224/3994/1295 +f 1235/4032/1291 1213/3966/1292 1234/4033/1294 +s 78 +f 1208/3961/1256 1231/4034/1284 1237/4035/1293 +f 1209/3962/1257 1231/4036/1284 1208/3961/1256 +f 1232/4037/1286 1219/4038/1267 1225/4039/1285 +f 1210/3963/1258 1219/4040/1267 1232/4041/1286 +f 1203/3958/1253 1204/3957/1252 1228/4001/1296 +f 1203/3958/1253 1236/4042/1297 1217/4043/1265 +f 1234/4044/1288 1224/3994/1272 1222/3990/1270 +f 1238/4045/1298 1217/4046/1265 1236/4047/1297 +f 1239/4048/1299 1217/4049/1265 1238/4045/1298 +f 1240/4050/1300 1239/4048/1299 1238/4045/1298 +f 1241/4051/1301 1239/4048/1299 1240/4050/1300 +f 1242/4052/1302 1241/4051/1301 1240/4050/1300 +f 1243/4053/1303 1241/4051/1301 1242/4052/1302 +f 1244/4054/1304 1243/4053/1303 1242/4052/1302 +f 1245/4055/1305 1243/4053/1303 1244/4054/1304 +f 1246/4056/1306 1245/4055/1305 1244/4054/1304 +f 1247/4057/1307 1245/4055/1305 1246/4056/1306 +f 1248/4058/1308 1247/4057/1307 1246/4056/1306 +f 1249/4059/1309 1247/4057/1307 1248/4058/1308 +f 1250/4060/1310 1249/4059/1309 1248/4058/1308 +f 1251/4061/1311 1249/4059/1309 1250/4060/1310 +f 1252/4062/1312 1251/4061/1311 1250/4060/1310 +f 1253/4063/1313 1251/4061/1311 1252/4062/1312 +f 1254/4064/1314 1253/4063/1313 1252/4062/1312 +f 1255/4065/1315 1253/4063/1313 1254/4064/1314 +f 1204/3957/1252 1256/4066/1316 1228/4001/1296 +f 1257/4067/1317 1256/4068/1316 1204/3957/1252 +f 1237/4069/1293 1257/4070/1317 1204/3957/1252 +f 1258/4071/1318 1257/4072/1317 1237/4073/1293 +f 1231/4074/1284 1258/4071/1318 1237/4075/1293 +f 1259/4076/1319 1258/4071/1318 1231/4077/1284 +f 1260/4078/1320 1259/4076/1319 1231/4079/1284 +f 1261/4080/1321 1259/4076/1319 1260/4078/1320 +f 1262/4081/1322 1261/4082/1321 1260/4078/1320 +f 1263/4083/1323 1261/4084/1321 1262/4081/1322 +f 1264/4085/1324 1263/4086/1323 1262/4081/1322 +f 1265/4087/1325 1263/4088/1323 1264/4089/1324 +f 1268/4090/1326 1267/4091/1327 1266/4092/1328 +f 1269/4093/1329 1267/4094/1327 1268/4095/1326 +f 1270/4096/1330 1269/4097/1329 1268/4098/1326 +f 1271/4099/1331 1269/4100/1329 1270/4096/1330 +f 1261/4101/1321 1271/4099/1331 1270/4096/1330 +f 1272/4102/1332 1271/4099/1331 1261/4103/1321 +f 1273/4104/1333 1272/4105/1332 1261/4106/1321 +f 1274/4107/1334 1272/4108/1332 1273/4109/1333 +f 1275/4110/1335 1274/4111/1334 1273/4112/1333 +f 1276/4113/1336 1274/4114/1334 1275/4110/1335 +f 1277/4115/1337 1276/4113/1336 1275/4110/1335 +f 1278/4116/1338 1276/4113/1336 1277/4115/1337 +f 1252/4062/1312 1279/4117/1339 1254/4064/1314 +f 1280/4118/1340 1279/4117/1339 1252/4062/1312 +f 1250/4060/1310 1280/4118/1340 1252/4062/1312 +f 1281/4119/1341 1280/4118/1340 1250/4060/1310 +f 1248/4058/1308 1281/4120/1341 1250/4060/1310 +f 1282/4121/1342 1281/4122/1341 1248/4058/1308 +f 1246/4056/1306 1282/4123/1342 1248/4058/1308 +f 1283/4124/1343 1282/4125/1342 1246/4056/1306 +f 1239/4048/1299 1220/3981/1268 1217/4126/1265 +f 1284/4127/1344 1220/3981/1268 1239/4048/1299 +f 1241/4051/1301 1284/4128/1344 1239/4048/1299 +f 1285/4129/1345 1284/4130/1344 1241/4051/1301 +f 1243/4053/1303 1285/4131/1345 1241/4051/1301 +f 1286/4132/1346 1285/4133/1345 1243/4053/1303 +f 1245/4055/1305 1286/4134/1346 1243/4053/1303 +f 1247/4057/1307 1286/4135/1346 1245/4055/1305 +f 1251/4061/1311 1285/4136/1345 1286/4137/1346 +f 1287/4138/1347 1285/4139/1345 1251/4061/1311 +f 1288/4140/1348 1287/4141/1347 1251/4061/1311 +f 1221/3986/1269 1287/4142/1347 1288/4143/1348 +f 1289/4144/1349 1221/3986/1269 1288/4145/1348 +f 1233/4146/1287 1221/3986/1269 1289/4144/1349 +f 1235/4147/1289 1233/4148/1287 1289/4144/1349 +f 1289/4144/1349 1290/4149/1350 1235/4150/1289 +f 1291/4151/1351 1290/4149/1350 1289/4144/1349 +f 1288/4152/1348 1291/4151/1351 1289/4144/1349 +f 1292/4153/1352 1291/4151/1351 1288/4154/1348 +f 1251/4061/1311 1292/4155/1352 1288/4156/1348 +f 1253/4063/1313 1292/4157/1352 1251/4061/1311 +f 1257/4158/1317 1266/4159/1328 1256/4160/1316 +f 1268/4161/1326 1266/4162/1328 1257/4163/1317 +f 1258/4071/1318 1268/4164/1326 1257/4165/1317 +f 1270/4096/1330 1268/4166/1326 1258/4071/1318 +f 1259/4076/1319 1270/4096/1330 1258/4071/1318 +f 1261/4167/1321 1270/4096/1330 1259/4076/1319 +f 1275/4110/1335 1293/4168/1353 1277/4115/1337 +f 1294/4169/1354 1293/4168/1353 1275/4110/1335 +f 1273/4170/1333 1294/4171/1354 1275/4110/1335 +f 1295/4172/1355 1294/4173/1354 1273/4174/1333 +f 1261/4175/1321 1295/4176/1355 1273/4177/1333 +f 1263/4178/1323 1295/4179/1355 1261/4180/1321 +f 1262/4081/1322 1296/4181/1356 1264/4182/1324 +f 1297/4183/1357 1296/4181/1356 1262/4081/1322 +f 1260/4078/1320 1297/4184/1357 1262/4081/1322 +f 1298/4185/1358 1297/4186/1357 1260/4078/1320 +f 1231/4187/1284 1298/4188/1358 1260/4078/1320 +f 1229/4002/1280 1298/4189/1358 1231/4190/1284 +s 79 +f 1254/4064/1359 1299/4191/1360 1255/4065/1361 +f 1240/4050/1362 1299/4192/1360 1254/4064/1359 +f 1300/4193/1363 1240/4050/1362 1254/4064/1359 +f 1242/4052/1364 1240/4050/1362 1300/4194/1363 +f 1244/4054/1365 1242/4052/1364 1300/4195/1363 +f 1265/4196/1366 1293/4168/1367 1301/4197/1368 +f 1266/4198/1369 1293/4168/1367 1265/4199/1366 +f 1296/4181/1370 1266/4200/1369 1265/4201/1366 +f 1256/4202/1371 1266/4203/1369 1296/4181/1370 +f 1228/4001/1278 1256/4204/1371 1296/4181/1370 +s 78 +f 1302/4205/1372 1282/4206/1342 1283/4207/1343 +f 1281/4208/1341 1282/4209/1342 1302/4210/1372 +f 1300/4211/1373 1281/4212/1341 1302/4213/1372 +f 1280/4118/1340 1281/4214/1341 1300/4215/1373 +f 1279/4117/1339 1280/4118/1340 1300/4216/1373 +f 1303/4217/1374 1276/4113/1336 1278/4116/1338 +f 1274/4218/1334 1276/4113/1336 1303/4219/1374 +f 1304/4220/1375 1274/4221/1334 1303/4222/1374 +f 1272/4223/1332 1274/4224/1334 1304/4225/1375 +f 1271/4099/1331 1272/4226/1332 1304/4227/1375 +f 1269/4228/1329 1305/4229/1376 1267/4230/1327 +f 1306/4231/1377 1305/4232/1376 1269/4233/1329 +f 1271/4099/1331 1306/4234/1377 1269/4235/1329 +f 1304/4236/1375 1306/4237/1377 1271/4099/1331 +s 79 +f 1299/4238/1360 1235/4239/1291 1290/4149/1378 +f 1236/4240/1290 1235/4241/1291 1299/4242/1360 +f 1238/4045/1379 1236/4243/1290 1299/4244/1360 +f 1283/4245/1380 1300/4246/1363 1302/4247/1381 +f 1244/4054/1365 1300/4248/1363 1283/4249/1380 +f 1246/4056/1382 1244/4054/1365 1283/4250/1380 +f 1278/4116/1383 1305/4251/1384 1303/4252/1385 +f 1293/4168/1367 1305/4253/1384 1278/4116/1383 +f 1277/4115/1386 1293/4168/1367 1278/4116/1383 +s 78 +f 1284/4254/1344 1221/3986/1269 1220/3981/1268 +f 1287/4255/1347 1221/3986/1269 1284/4256/1344 +f 1285/4257/1345 1287/4258/1347 1284/4259/1344 +s 79 +f 1227/3998/1276 1296/4181/1370 1307/4260/1387 +f 1228/4001/1278 1296/4181/1370 1227/3998/1276 +f 1293/4168/1367 1267/4261/1388 1305/4262/1384 +f 1266/4263/1369 1267/4264/1388 1293/4168/1367 +s 78 +f 1249/4059/1309 1286/4265/1346 1247/4057/1307 +f 1251/4061/1311 1286/4266/1346 1249/4059/1309 +f 1255/4065/1315 1292/4267/1352 1253/4063/1313 +f 1299/4268/1389 1292/4269/1352 1255/4065/1315 +f 1299/4270/1389 1291/4151/1351 1292/4271/1352 +f 1290/4149/1350 1291/4151/1351 1299/4272/1389 +f 1303/4273/1374 1306/4274/1377 1304/4275/1375 +f 1305/4276/1376 1306/4277/1377 1303/4278/1374 +f 1294/4279/1354 1301/4280/1390 1293/4168/1353 +f 1295/4281/1355 1301/4282/1390 1294/4283/1354 +f 1265/4284/1325 1295/4285/1355 1263/4286/1323 +f 1301/4287/1390 1295/4288/1355 1265/4289/1325 +f 1297/4290/1357 1307/4291/1391 1296/4181/1356 +f 1298/4292/1358 1307/4293/1391 1297/4294/1357 +f 1227/3998/1282 1298/4295/1358 1229/4002/1280 +f 1307/4296/1391 1298/4297/1358 1227/3998/1282 +s 79 +f 1254/4064/1359 1279/4117/1392 1300/4298/1363 +f 1265/4299/1366 1264/4300/1393 1296/4181/1370 +f 1240/4050/1362 1238/4045/1379 1299/4301/1360 +s 85 +f 1310/4302/1394 1309/4303/1395 1308/4304/1396 +f 1311/4305/1397 1309/4303/1395 1310/4302/1394 +f 1312/4306/1398 1311/4305/1397 1310/4302/1394 +f 1313/4307/1399 1311/4305/1397 1312/4306/1398 +f 1314/4308/1400 1313/4307/1399 1312/4306/1398 +f 1315/4309/1401 1313/4307/1399 1314/4308/1400 +f 1316/4310/1402 1315/4309/1401 1314/4308/1400 +f 1317/4311/1403 1315/4309/1401 1316/4310/1402 +f 1318/4312/1404 1317/4311/1403 1316/4310/1402 +f 1319/4313/1405 1317/4311/1403 1318/4312/1404 +f 1320/4314/1406 1319/4313/1405 1318/4312/1404 +f 1321/4315/1407 1319/4313/1405 1320/4314/1406 +f 1322/4316/1408 1321/4315/1407 1320/4314/1406 +f 1323/4317/1409 1321/4315/1407 1322/4316/1408 +f 1324/4318/1410 1323/4317/1409 1322/4316/1408 +f 1325/4319/1411 1323/4317/1409 1324/4318/1410 +f 1326/4320/1412 1325/4319/1411 1324/4318/1410 +f 1327/4321/1413 1325/4319/1411 1326/4320/1412 +f 1328/4322/1414 1327/4321/1413 1326/4320/1412 +f 1329/4323/1415 1327/4321/1413 1328/4322/1414 +f 1330/4324/1416 1329/4323/1415 1328/4322/1414 +f 1331/4325/1417 1329/4323/1415 1330/4324/1416 +f 1332/4326/1418 1331/4325/1417 1330/4324/1416 +f 1333/4327/1419 1331/4325/1417 1332/4326/1418 +f 1334/4328/1420 1333/4327/1419 1332/4326/1418 +s 86 +f 1309/4303/1421 1335/4329/1422 1308/4304/1423 +f 1336/4330/1424 1335/4329/1422 1309/4303/1421 +f 1311/4305/1425 1336/4330/1424 1309/4303/1421 +f 1337/4331/1426 1336/4330/1424 1311/4305/1425 +f 1313/4307/1427 1337/4331/1426 1311/4305/1425 +f 1338/4332/1428 1337/4331/1426 1313/4307/1427 +f 1315/4309/1429 1338/4332/1428 1313/4307/1427 +f 1339/4333/1430 1338/4332/1428 1315/4309/1429 +f 1317/4311/1431 1339/4333/1430 1315/4309/1429 +f 1340/4334/1432 1339/4333/1430 1317/4311/1431 +f 1319/4313/1433 1340/4334/1432 1317/4311/1431 +f 1341/4335/1434 1340/4334/1432 1319/4313/1433 +f 1321/4315/1435 1341/4335/1434 1319/4313/1433 +f 1342/4336/1436 1341/4335/1434 1321/4315/1435 +f 1323/4317/1437 1342/4336/1436 1321/4315/1435 +f 1343/4337/1438 1342/4336/1436 1323/4317/1437 +f 1325/4319/1439 1343/4337/1438 1323/4317/1437 +f 1344/4338/1440 1343/4337/1438 1325/4319/1439 +f 1327/4321/1441 1344/4338/1440 1325/4319/1439 +f 1345/4339/1442 1344/4338/1440 1327/4321/1441 +f 1329/4323/1443 1345/4339/1442 1327/4321/1441 +f 1331/4325/1444 1345/4339/1442 1329/4323/1443 +s 85 +f 1348/4340/1445 1347/4341/1446 1346/4342/1447 +f 1349/4343/1448 1347/4341/1446 1348/4340/1445 +f 1350/4344/1449 1349/4343/1448 1348/4340/1445 +f 1351/4345/1450 1349/4343/1448 1350/4344/1449 +f 1352/4346/1451 1351/4345/1450 1350/4344/1449 +f 1353/4347/1452 1351/4345/1450 1352/4346/1451 +f 1354/4348/1453 1353/4347/1452 1352/4346/1451 +f 1355/4349/1454 1353/4347/1452 1354/4348/1453 +f 1356/4350/1455 1355/4349/1454 1354/4348/1453 +f 1357/4351/1456 1355/4349/1454 1356/4350/1455 +f 1358/4352/1457 1357/4351/1456 1356/4350/1455 +f 1359/4353/1458 1357/4351/1456 1358/4352/1457 +f 1360/4354/1459 1359/4353/1458 1358/4352/1457 +f 1361/4355/1460 1359/4353/1458 1360/4354/1459 +f 1362/4356/1461 1361/4355/1460 1360/4354/1459 +f 1312/4306/1398 1361/4355/1460 1362/4356/1461 +f 1314/4308/1400 1312/4306/1398 1362/4356/1461 +f 1363/4357/1462 1310/4302/1394 1308/4304/1396 +f 1364/4358/1463 1310/4302/1394 1363/4357/1462 +f 1365/4359/1464 1364/4358/1463 1363/4357/1462 +f 1366/4360/1465 1364/4358/1463 1365/4359/1464 +f 1367/4361/1466 1366/4360/1465 1365/4359/1464 +f 1368/4362/1467 1366/4360/1465 1367/4361/1466 +f 1369/4363/1468 1368/4362/1467 1367/4361/1466 +f 1347/4341/1446 1368/4362/1467 1369/4363/1468 +f 1370/4364/1469 1347/4341/1446 1369/4363/1468 +f 1346/4342/1447 1347/4341/1446 1370/4365/1469 +f 1371/4366/1470 1346/4342/1447 1370/4367/1469 +f 1372/4368/1471 1346/4342/1447 1371/4366/1470 +f 1373/4369/1472 1372/4368/1471 1371/4366/1470 +f 1332/4326/1418 1372/4368/1471 1373/4369/1472 +f 1334/4328/1420 1332/4326/1418 1373/4369/1472 +f 1373/4369/1472 1374/4370/1473 1334/4328/1420 +f 1375/4371/1474 1374/4370/1473 1373/4369/1472 +f 1371/4366/1470 1375/4371/1474 1373/4369/1472 +f 1376/4372/1475 1375/4371/1474 1371/4366/1470 +f 1377/4373/1476 1376/4372/1475 1371/4366/1470 +f 1378/4374/1477 1376/4372/1475 1377/4373/1476 +f 1379/4375/1478 1378/4376/1477 1377/4373/1476 +f 1380/4377/1479 1378/4378/1477 1379/4379/1478 +f 1365/4359/1464 1380/4380/1479 1379/4381/1478 +f 1381/4382/1480 1380/4383/1479 1365/4359/1464 +f 1363/4357/1462 1381/4382/1480 1365/4359/1464 +f 1308/4304/1396 1381/4382/1480 1363/4357/1462 +s 88 +f 1384/4384/1481 1383/4385/1482 1382/4386/1483 +f 1385/4387/1484 1383/4385/1482 1384/4384/1481 +f 1386/4388/1485 1385/4389/1484 1384/4384/1481 +f 1387/4390/1486 1385/4391/1484 1386/4388/1485 +f 1388/4392/1487 1387/4390/1486 1386/4388/1485 +f 1374/4370/1488 1387/4390/1486 1388/4392/1487 +f 1389/4393/1489 1374/4370/1488 1388/4392/1487 +f 1334/4328/1490 1374/4370/1488 1389/4393/1489 +f 1390/4394/1491 1334/4328/1490 1389/4393/1489 +f 1333/4327/1492 1334/4328/1490 1390/4394/1491 +f 1391/4395/1493 1333/4327/1492 1390/4394/1491 +s 85 +f 1392/4396/1494 1350/4344/1449 1348/4340/1445 +f 1352/4346/1451 1350/4344/1449 1392/4396/1494 +f 1393/4397/1495 1352/4346/1451 1392/4396/1494 +f 1394/4398/1496 1352/4346/1451 1393/4397/1495 +f 1395/4399/1497 1394/4398/1496 1393/4397/1495 +f 1396/4400/1498 1394/4398/1496 1395/4399/1497 +f 1397/4401/1499 1396/4400/1498 1395/4399/1497 +f 1398/4402/1500 1396/4400/1498 1397/4401/1499 +f 1322/4316/1408 1398/4402/1500 1397/4401/1499 +f 1320/4314/1406 1398/4402/1500 1322/4316/1408 +s 89 +f 1335/4403/1501 1331/4404/1502 1308/4405/1503 +f 1345/4406/1504 1331/4404/1502 1335/4403/1501 +f 1336/4407/1505 1345/4406/1504 1335/4403/1501 +f 1344/4408/1506 1345/4406/1504 1336/4407/1505 +f 1337/4409/1507 1344/4408/1506 1336/4407/1505 +f 1343/4410/1508 1344/4408/1506 1337/4409/1507 +f 1338/4411/1509 1343/4410/1508 1337/4409/1507 +f 1342/4412/1510 1343/4410/1508 1338/4411/1509 +f 1339/4413/1511 1342/4412/1510 1338/4411/1509 +s 85 +f 1399/4414/1512 1381/4382/1480 1308/4304/1396 +f 1380/4415/1479 1381/4382/1480 1399/4414/1512 +f 1383/4385/1513 1380/4416/1479 1399/4414/1512 +f 1378/4417/1477 1380/4418/1479 1383/4385/1513 +f 1385/4419/1514 1378/4420/1477 1383/4385/1513 +f 1376/4372/1475 1378/4421/1477 1385/4422/1514 +f 1387/4390/1515 1376/4372/1475 1385/4423/1514 +f 1375/4371/1474 1376/4372/1475 1387/4390/1515 +f 1374/4370/1473 1375/4371/1474 1387/4390/1515 +f 1318/4312/1404 1398/4402/1500 1320/4314/1406 +f 1400/4424/1516 1398/4402/1500 1318/4312/1404 +f 1401/4425/1517 1400/4426/1516 1318/4312/1404 +f 1402/4427/1518 1400/4428/1516 1401/4425/1517 +f 1403/4429/1519 1402/4427/1518 1401/4425/1517 +f 1404/4430/1520 1402/4427/1518 1403/4429/1519 +f 1405/4431/1521 1404/4432/1520 1403/4429/1519 +f 1356/4350/1455 1404/4433/1520 1405/4434/1521 +f 1358/4352/1457 1356/4350/1455 1405/4435/1521 +s 90 +f 1391/4436/1522 1407/4437/1523 1406/4438/1524 +f 1382/4439/1525 1407/4437/1523 1391/4436/1522 +f 1390/4440/1526 1382/4439/1525 1391/4436/1522 +f 1384/4441/1527 1382/4439/1525 1390/4440/1526 +f 1389/4442/1528 1384/4441/1527 1390/4440/1526 +f 1386/4443/1529 1384/4441/1527 1389/4442/1528 +s 85 +f 1408/4444/1530 1392/4396/1494 1348/4340/1445 +f 1409/4445/1531 1392/4396/1494 1408/4444/1530 +f 1410/4446/1532 1409/4445/1531 1408/4444/1530 +f 1411/4447/1533 1409/4445/1531 1410/4446/1532 +f 1330/4324/1416 1411/4447/1533 1410/4446/1532 +f 1328/4322/1414 1411/4447/1533 1330/4324/1416 +f 1379/4448/1478 1367/4361/1466 1365/4359/1464 +f 1369/4363/1468 1367/4361/1466 1379/4449/1478 +f 1377/4373/1476 1369/4363/1468 1379/4450/1478 +f 1370/4451/1469 1369/4363/1468 1377/4373/1476 +f 1371/4366/1470 1370/4452/1469 1377/4373/1476 +f 1409/4445/1531 1393/4397/1495 1392/4396/1494 +f 1395/4399/1497 1393/4397/1495 1409/4445/1531 +f 1412/4453/1534 1395/4399/1497 1409/4445/1531 +f 1397/4401/1499 1395/4399/1497 1412/4454/1534 +f 1322/4316/1408 1397/4401/1499 1412/4455/1534 +f 1349/4343/1448 1368/4362/1467 1347/4341/1446 +f 1413/4456/1535 1368/4362/1467 1349/4343/1448 +f 1357/4351/1456 1413/4456/1535 1349/4343/1448 +f 1359/4353/1458 1413/4456/1535 1357/4351/1456 +f 1362/4356/1461 1401/4425/1517 1314/4308/1400 +f 1414/4457/1536 1401/4425/1517 1362/4356/1461 +f 1360/4354/1459 1414/4457/1536 1362/4356/1461 +f 1358/4352/1457 1414/4457/1536 1360/4354/1459 +f 1394/4398/1496 1415/4458/1537 1352/4346/1451 +f 1416/4459/1538 1415/4458/1537 1394/4398/1496 +f 1396/4400/1498 1416/4459/1538 1394/4398/1496 +f 1398/4402/1500 1416/4459/1538 1396/4400/1498 +s 88 +f 1382/4386/1483 1308/4304/1539 1407/4460/1540 +f 1399/4414/1541 1308/4304/1539 1382/4386/1483 +f 1383/4385/1482 1399/4414/1541 1382/4386/1483 +s 85 +f 1349/4343/1448 1355/4349/1454 1357/4351/1456 +f 1353/4347/1452 1355/4349/1454 1349/4343/1448 +f 1351/4345/1450 1353/4347/1452 1349/4343/1448 +f 1411/4447/1533 1412/4461/1534 1409/4445/1531 +f 1326/4320/1412 1412/4462/1534 1411/4447/1533 +f 1328/4322/1414 1326/4320/1412 1411/4447/1533 +f 1410/4446/1532 1332/4326/1418 1330/4324/1416 +f 1372/4368/1471 1332/4326/1418 1410/4446/1532 +f 1408/4444/1530 1372/4368/1471 1410/4446/1532 +f 1415/4458/1537 1354/4348/1453 1352/4346/1451 +f 1356/4350/1455 1354/4348/1453 1415/4458/1537 +f 1404/4463/1520 1356/4350/1455 1415/4458/1537 +s 92 +f 1406/4438/1542 1308/4405/1543 1331/4404/1544 +f 1407/4437/1545 1308/4405/1543 1406/4438/1542 +s 85 +f 1405/4464/1521 1414/4457/1536 1358/4352/1457 +f 1403/4429/1519 1414/4457/1536 1405/4465/1521 +f 1413/4456/1535 1366/4360/1465 1368/4362/1467 +f 1359/4353/1458 1366/4360/1465 1413/4456/1535 +f 1346/4342/1447 1408/4444/1530 1348/4340/1445 +f 1372/4368/1471 1408/4444/1530 1346/4342/1447 +f 1359/4353/1458 1364/4358/1463 1366/4360/1465 +f 1361/4355/1460 1364/4358/1463 1359/4353/1458 +f 1361/4355/1460 1310/4302/1394 1364/4358/1463 +f 1312/4306/1398 1310/4302/1394 1361/4355/1460 +f 1412/4466/1534 1324/4318/1410 1322/4316/1408 +f 1326/4320/1412 1324/4318/1410 1412/4467/1534 +s 88 +f 1331/4325/1546 1391/4395/1493 1406/4468/1547 +f 1333/4327/1492 1391/4395/1493 1331/4325/1546 +s 89 +f 1341/4469/1548 1339/4413/1511 1340/4470/1549 +f 1342/4412/1510 1339/4413/1511 1341/4469/1548 +s 85 +f 1316/4310/1402 1401/4425/1517 1318/4312/1404 +f 1314/4308/1400 1401/4425/1517 1316/4310/1402 +f 1415/4458/1537 1402/4427/1518 1404/4471/1520 +f 1416/4459/1538 1402/4427/1518 1415/4458/1537 +f 1416/4459/1538 1400/4472/1516 1402/4427/1518 +f 1398/4402/1500 1400/4473/1516 1416/4459/1538 +s 90 +f 1389/4474/1528 1388/4475/1550 1386/4476/1529 +s 85 +f 1414/4457/1536 1403/4429/1519 1401/4425/1517 +s 93 +f 1419/4477/1551 1418/4478/1552 1417/4479/1553 +f 1420/4480/1554 1418/4478/1552 1419/4477/1551 +f 1421/4481/1555 1420/4480/1554 1419/4477/1551 +f 1422/4482/1556 1420/4480/1554 1421/4481/1555 +f 1423/4483/1557 1422/4482/1556 1421/4481/1555 +f 1424/4484/1558 1422/4482/1556 1423/4483/1557 +f 1425/4485/1559 1424/4484/1558 1423/4483/1557 +f 1426/4486/1560 1424/4484/1558 1425/4485/1559 +f 1427/4487/1561 1426/4486/1560 1425/4485/1559 +f 1428/4488/1562 1426/4486/1560 1427/4487/1561 +f 1429/4489/1563 1428/4488/1562 1427/4487/1561 +f 1430/4490/1564 1428/4488/1562 1429/4489/1563 +f 1431/4491/1565 1430/4490/1564 1429/4489/1563 +f 1432/4492/1566 1430/4490/1564 1431/4491/1565 +f 1433/4493/1567 1432/4492/1566 1431/4491/1565 +f 1434/4494/1568 1432/4492/1566 1433/4495/1567 +f 1435/4496/1569 1434/4494/1568 1433/4497/1567 +f 1436/4498/1570 1434/4494/1568 1435/4496/1569 +f 1437/4499/1571 1436/4498/1570 1435/4496/1569 +f 1438/4500/1572 1436/4498/1570 1437/4499/1571 +f 1439/4501/1573 1438/4500/1572 1437/4499/1571 +f 1440/4502/1574 1438/4500/1572 1439/4501/1573 +f 1441/4503/1575 1440/4502/1574 1439/4501/1573 +f 1442/4504/1576 1440/4502/1574 1441/4503/1575 +f 1443/4505/1577 1442/4504/1576 1441/4503/1575 +f 1444/4506/1578 1442/4504/1576 1443/4505/1577 +f 1445/4507/1579 1444/4506/1578 1443/4505/1577 +f 1446/4508/1580 1444/4506/1578 1445/4507/1579 +f 1447/4509/1581 1446/4508/1580 1445/4507/1579 +f 1448/4510/1582 1446/4508/1580 1447/4509/1581 +f 1449/4511/1583 1448/4510/1582 1447/4509/1581 +f 1450/4512/1584 1448/4510/1582 1449/4511/1583 +f 1451/4513/1585 1450/4512/1584 1449/4511/1583 +f 1452/4514/1586 1450/4512/1584 1451/4513/1585 +f 1453/4515/1587 1452/4514/1586 1451/4513/1585 +f 1454/4516/1588 1452/4514/1586 1453/4515/1587 +f 1455/4517/1589 1454/4516/1588 1453/4515/1587 +f 1456/4518/1590 1454/4516/1588 1455/4519/1589 +f 1457/4520/1591 1456/4518/1590 1455/4521/1589 +f 1458/4522/1592 1456/4518/1590 1457/4523/1591 +f 1459/4524/1593 1458/4522/1592 1457/4525/1591 +f 1460/4526/1594 1458/4522/1592 1459/4527/1593 +f 1461/4528/1595 1460/4529/1594 1459/4530/1593 +f 1462/4531/1596 1460/4532/1594 1461/4533/1595 +f 1463/4534/1597 1462/4535/1596 1461/4536/1595 +f 1464/4537/1598 1462/4538/1596 1463/4534/1597 +f 1465/4539/1599 1464/4537/1598 1463/4534/1597 +f 1466/4540/1600 1464/4537/1598 1465/4539/1599 +f 1467/4541/1601 1466/4540/1600 1465/4539/1599 +f 1468/4542/1602 1466/4540/1600 1467/4541/1601 +f 1469/4543/1603 1468/4542/1602 1467/4541/1601 +f 1470/4544/1604 1468/4542/1602 1469/4543/1603 +f 1471/4545/1605 1470/4544/1604 1469/4543/1603 +f 1472/4546/1606 1470/4544/1604 1471/4545/1605 +f 1473/4547/1607 1472/4546/1606 1471/4545/1605 +f 1418/4478/1552 1472/4546/1606 1473/4547/1607 +f 1420/4480/1554 1472/4546/1606 1418/4478/1552 +f 1474/4548/1608 1472/4546/1606 1420/4480/1554 +f 1422/4482/1556 1474/4548/1608 1420/4480/1554 +f 1475/4549/1609 1474/4548/1608 1422/4482/1556 +f 1424/4484/1558 1475/4549/1609 1422/4482/1556 +f 1476/4550/1610 1475/4549/1609 1424/4484/1558 +f 1426/4486/1560 1476/4550/1610 1424/4484/1558 +f 1477/4551/1611 1476/4550/1610 1426/4486/1560 +f 1428/4488/1562 1477/4551/1611 1426/4486/1560 +f 1478/4552/1612 1477/4551/1611 1428/4488/1562 +f 1430/4490/1564 1478/4553/1612 1428/4488/1562 +f 1479/4554/1613 1478/4555/1612 1430/4490/1564 +f 1432/4492/1566 1479/4556/1613 1430/4490/1564 +f 1480/4557/1614 1479/4558/1613 1432/4492/1566 +f 1434/4494/1568 1480/4557/1614 1432/4492/1566 +f 1481/4559/1615 1480/4557/1614 1434/4494/1568 +f 1436/4498/1570 1481/4559/1615 1434/4494/1568 +f 1482/4560/1616 1481/4559/1615 1436/4498/1570 +f 1438/4500/1572 1482/4560/1616 1436/4498/1570 +f 1483/4561/1617 1482/4560/1616 1438/4500/1572 +f 1440/4502/1574 1483/4561/1617 1438/4500/1572 +f 1484/4562/1618 1483/4561/1617 1440/4502/1574 +f 1442/4504/1576 1484/4562/1618 1440/4502/1574 +f 1485/4563/1619 1484/4562/1618 1442/4504/1576 +f 1444/4506/1578 1485/4563/1619 1442/4504/1576 +f 1446/4508/1580 1485/4563/1619 1444/4506/1578 +f 1486/4564/1620 1421/4481/1555 1419/4477/1551 +f 1487/4565/1621 1421/4481/1555 1486/4564/1620 +f 1488/4566/1622 1487/4565/1621 1486/4564/1620 +f 1489/4567/1623 1487/4565/1621 1488/4566/1622 +f 1490/4568/1624 1489/4567/1623 1488/4566/1622 +f 1491/4569/1625 1489/4567/1623 1490/4568/1624 +f 1492/4570/1626 1491/4569/1625 1490/4568/1624 +f 1493/4571/1627 1491/4569/1625 1492/4570/1626 +f 1494/4572/1628 1493/4571/1627 1492/4570/1626 +f 1495/4573/1629 1493/4571/1627 1494/4572/1628 +f 1496/4574/1630 1495/4573/1629 1494/4572/1628 +f 1497/4575/1631 1495/4573/1629 1496/4576/1630 +f 1498/4577/1632 1497/4578/1631 1496/4579/1630 +f 1499/4580/1633 1497/4581/1631 1498/4582/1632 +f 1500/4583/1634 1499/4584/1633 1498/4585/1632 +f 1501/4586/1635 1499/4587/1633 1500/4588/1634 +f 1502/4589/1636 1501/4590/1635 1500/4591/1634 +f 1503/4592/1637 1501/4593/1635 1502/4594/1636 +f 1504/4595/1638 1503/4592/1637 1502/4596/1636 +f 1505/4597/1639 1503/4592/1637 1504/4595/1638 +f 1506/4598/1640 1505/4597/1639 1504/4595/1638 +f 1507/4599/1641 1505/4597/1639 1506/4598/1640 +f 1474/4548/1608 1470/4544/1604 1472/4546/1606 +f 1508/4600/1642 1470/4544/1604 1474/4548/1608 +f 1475/4549/1609 1508/4600/1642 1474/4548/1608 +f 1509/4601/1643 1508/4600/1642 1475/4549/1609 +f 1476/4550/1610 1509/4602/1643 1475/4549/1609 +f 1510/4603/1644 1509/4604/1643 1476/4550/1610 +f 1477/4551/1611 1510/4605/1644 1476/4550/1610 +f 1511/4606/1645 1510/4607/1644 1477/4551/1611 +f 1478/4608/1612 1511/4609/1645 1477/4551/1611 +f 1512/4610/1646 1511/4611/1645 1478/4612/1612 +f 1479/4613/1613 1512/4614/1646 1478/4615/1612 +f 1513/4616/1647 1512/4617/1646 1479/4618/1613 +f 1480/4557/1614 1513/4619/1647 1479/4620/1613 +f 1514/4621/1648 1513/4622/1647 1480/4557/1614 +f 1481/4559/1615 1514/4621/1648 1480/4557/1614 +f 1515/4623/1649 1514/4621/1648 1481/4559/1615 +f 1482/4560/1616 1515/4623/1649 1481/4559/1615 +f 1516/4624/1650 1515/4623/1649 1482/4560/1616 +f 1483/4561/1617 1516/4624/1650 1482/4560/1616 +f 1484/4562/1618 1516/4624/1650 1483/4561/1617 +f 1508/4600/1642 1468/4542/1602 1470/4544/1604 +f 1517/4625/1651 1468/4542/1602 1508/4600/1642 +f 1509/4626/1643 1517/4627/1651 1508/4600/1642 +f 1518/4628/1652 1517/4629/1651 1509/4630/1643 +f 1510/4631/1644 1518/4632/1652 1509/4633/1643 +f 1519/4634/1653 1518/4635/1652 1510/4636/1644 +f 1511/4637/1645 1519/4638/1653 1510/4639/1644 +f 1520/4640/1654 1519/4641/1653 1511/4642/1645 +f 1512/4643/1646 1520/4644/1654 1511/4645/1645 +f 1521/4646/1655 1520/4647/1654 1512/4648/1646 +f 1513/4649/1647 1521/4650/1655 1512/4651/1646 +f 1522/4652/1656 1521/4653/1655 1513/4654/1647 +f 1514/4621/1648 1522/4655/1656 1513/4656/1647 +f 1523/4657/1657 1522/4658/1656 1514/4621/1648 +f 1515/4623/1649 1523/4657/1657 1514/4621/1648 +f 1524/4659/1658 1523/4657/1657 1515/4623/1649 +f 1516/4624/1650 1524/4659/1658 1515/4623/1649 +f 1525/4660/1659 1524/4659/1658 1516/4624/1650 +f 1526/4661/1660 1525/4660/1659 1516/4624/1650 +f 1527/4662/1661 1525/4660/1659 1526/4661/1660 +f 1528/4663/1662 1490/4568/1624 1488/4566/1622 +f 1529/4664/1663 1490/4568/1624 1528/4663/1662 +f 1530/4665/1664 1529/4664/1663 1528/4663/1662 +f 1531/4666/1665 1529/4664/1663 1530/4665/1664 +f 1532/4667/1666 1531/4666/1665 1530/4665/1664 +f 1533/4668/1667 1531/4666/1665 1532/4669/1666 +f 1534/4670/1668 1533/4671/1667 1532/4672/1666 +f 1535/4673/1669 1533/4674/1667 1534/4675/1668 +f 1536/4676/1670 1535/4677/1669 1534/4678/1668 +f 1537/4679/1671 1535/4680/1669 1536/4681/1670 +f 1538/4682/1672 1537/4683/1671 1536/4684/1670 +f 1539/4685/1673 1537/4686/1671 1538/4687/1672 +f 1540/4688/1674 1539/4689/1673 1538/4690/1672 +f 1541/4691/1675 1539/4692/1673 1540/4693/1674 +f 1542/4694/1676 1541/4695/1675 1540/4696/1674 +f 1543/4697/1677 1541/4698/1675 1542/4699/1676 +f 1546/4700/1678 1545/4701/1679 1544/4702/1680 +f 1547/4703/1681 1545/4704/1679 1546/4705/1678 +f 1548/4706/1682 1547/4707/1681 1546/4708/1678 +f 1542/4709/1676 1547/4710/1681 1548/4711/1682 +f 1549/4712/1683 1542/4713/1676 1548/4714/1682 +f 1543/4715/1677 1542/4716/1676 1549/4717/1683 +f 1550/4718/1684 1543/4719/1677 1549/4720/1683 +f 1506/4598/1640 1543/4721/1677 1550/4722/1684 +f 1551/4723/1685 1506/4598/1640 1550/4724/1684 +f 1507/4599/1641 1506/4598/1640 1551/4725/1685 +f 1552/4726/1686 1507/4599/1641 1551/4727/1685 +f 1443/4505/1577 1507/4599/1641 1552/4728/1686 +f 1445/4507/1579 1443/4505/1577 1552/4729/1686 +f 1517/4730/1651 1466/4540/1600 1468/4542/1602 +f 1553/4731/1687 1466/4540/1600 1517/4732/1651 +f 1518/4733/1652 1553/4734/1687 1517/4735/1651 +f 1554/4736/1688 1553/4737/1687 1518/4738/1652 +f 1519/4739/1653 1554/4740/1688 1518/4741/1652 +f 1555/4742/1689 1554/4743/1688 1519/4744/1653 +f 1520/4745/1654 1555/4746/1689 1519/4747/1653 +f 1556/4748/1690 1555/4749/1689 1520/4750/1654 +f 1521/4751/1655 1556/4752/1690 1520/4753/1654 +f 1557/4754/1691 1556/4755/1690 1521/4756/1655 +f 1522/4757/1656 1557/4758/1691 1521/4759/1655 +f 1558/4760/1692 1557/4761/1691 1522/4762/1656 +f 1559/4763/1693 1462/4764/1596 1464/4537/1598 +f 1560/4765/1694 1462/4766/1596 1559/4767/1693 +f 1561/4768/1695 1560/4769/1694 1559/4770/1693 +f 1562/4771/1696 1560/4772/1694 1561/4773/1695 +f 1563/4774/1697 1562/4775/1696 1561/4776/1695 +f 1564/4777/1698 1562/4778/1696 1563/4779/1697 +f 1557/4780/1691 1564/4781/1698 1563/4782/1697 +f 1565/4783/1699 1564/4784/1698 1557/4785/1691 +f 1558/4786/1692 1565/4787/1699 1557/4788/1691 +f 1527/4662/1661 1565/4789/1699 1558/4790/1692 +f 1566/4791/1700 1532/4792/1666 1530/4665/1664 +f 1534/4793/1668 1532/4794/1666 1566/4795/1700 +f 1567/4796/1701 1534/4797/1668 1566/4798/1700 +f 1536/4799/1670 1534/4800/1668 1567/4801/1701 +f 1568/4802/1702 1536/4803/1670 1567/4804/1701 +f 1538/4805/1672 1536/4806/1670 1568/4807/1702 +f 1569/4808/1703 1538/4809/1672 1568/4810/1702 +f 1540/4811/1674 1538/4812/1672 1569/4813/1703 +f 1547/4814/1681 1540/4815/1674 1569/4816/1703 +f 1542/4817/1676 1540/4818/1674 1547/4819/1681 +f 1572/4820/1704 1571/4821/1705 1570/4822/1706 +f 1573/4823/1707 1571/4821/1705 1572/4820/1704 +f 1574/4824/1708 1573/4823/1707 1572/4820/1704 +f 1575/4825/1709 1573/4823/1707 1574/4824/1708 +f 1576/4826/1710 1575/4825/1709 1574/4824/1708 +f 1577/4827/1711 1575/4825/1709 1576/4826/1710 +f 1578/4828/1712 1577/4827/1711 1576/4826/1710 +f 1579/4829/1713 1577/4827/1711 1578/4828/1712 +f 1546/4830/1714 1579/4829/1713 1578/4828/1712 +f 1544/4831/1680 1579/4829/1713 1546/4830/1714 +f 1580/4832/1715 1579/4833/1713 1544/4834/1680 +f 1577/4835/1711 1579/4833/1713 1580/4832/1715 +f 1581/4836/1716 1577/4835/1711 1580/4832/1715 +f 1575/4837/1709 1577/4835/1711 1581/4836/1716 +f 1582/4838/1717 1575/4837/1709 1581/4836/1716 +f 1573/4839/1707 1575/4837/1709 1582/4838/1717 +f 1583/4840/1718 1573/4839/1707 1582/4838/1717 +f 1571/4841/1705 1573/4839/1707 1583/4840/1718 +f 1584/4842/1719 1571/4841/1705 1583/4840/1718 +f 1504/4595/1638 1543/4843/1677 1506/4598/1640 +f 1541/4844/1675 1543/4845/1677 1504/4595/1638 +f 1502/4846/1636 1541/4847/1675 1504/4595/1638 +f 1539/4848/1673 1541/4849/1675 1502/4850/1636 +f 1500/4851/1634 1539/4852/1673 1502/4853/1636 +f 1537/4854/1671 1539/4855/1673 1500/4856/1634 +f 1498/4857/1632 1537/4858/1671 1500/4859/1634 +f 1535/4860/1669 1537/4861/1671 1498/4862/1632 +f 1496/4863/1630 1535/4864/1669 1498/4865/1632 +f 1587/4866/1720 1586/4867/1721 1585/4868/1722 +f 1588/4869/1723 1586/4867/1721 1587/4866/1720 +f 1589/4870/1724 1588/4869/1723 1587/4866/1720 +f 1590/4871/1725 1588/4869/1723 1589/4870/1724 +f 1591/4872/1726 1590/4871/1725 1589/4870/1724 +f 1592/4873/1727 1590/4871/1725 1591/4872/1726 +f 1593/4874/1728 1592/4873/1727 1591/4872/1726 +f 1467/4541/1601 1592/4873/1727 1593/4874/1728 +f 1469/4543/1603 1467/4541/1601 1593/4874/1728 +f 1553/4875/1687 1464/4537/1598 1466/4540/1600 +f 1559/4876/1693 1464/4537/1598 1553/4877/1687 +f 1554/4878/1688 1559/4879/1693 1553/4880/1687 +f 1561/4881/1695 1559/4882/1693 1554/4883/1688 +f 1555/4884/1689 1561/4885/1695 1554/4886/1688 +f 1563/4887/1697 1561/4888/1695 1555/4889/1689 +f 1556/4890/1690 1563/4891/1697 1555/4892/1689 +f 1557/4893/1691 1563/4894/1697 1556/4895/1690 +f 1594/4896/1729 1454/4516/1588 1456/4518/1590 +f 1595/4897/1730 1454/4516/1588 1594/4896/1729 +f 1596/4898/1731 1595/4899/1730 1594/4896/1729 +f 1597/4900/1732 1595/4901/1730 1596/4898/1731 +f 1527/4662/1733 1597/4900/1732 1596/4898/1731 +f 1598/4902/1734 1597/4900/1732 1527/4662/1733 +f 1526/4661/1660 1598/4902/1734 1527/4662/1733 +f 1485/4563/1619 1598/4902/1734 1526/4661/1660 +f 1601/4903/1735 1600/4904/1736 1599/4905/1737 +f 1602/4906/1738 1600/4904/1736 1601/4903/1735 +f 1603/4907/1739 1602/4908/1738 1601/4903/1735 +f 1604/4909/1740 1602/4910/1738 1603/4911/1739 +f 1605/4912/1741 1604/4913/1740 1603/4914/1739 +f 1551/4915/1685 1604/4916/1740 1605/4917/1741 +f 1552/4918/1686 1551/4919/1685 1605/4920/1741 +f 1587/4921/1720 1603/4922/1739 1601/4903/1735 +f 1606/4923/1742 1603/4924/1739 1587/4921/1720 +f 1585/4925/1722 1606/4923/1742 1587/4921/1720 +f 1607/4926/1743 1606/4923/1742 1585/4925/1722 +f 1608/4927/1744 1607/4926/1743 1585/4925/1722 +f 1449/4511/1583 1607/4926/1743 1608/4927/1744 +f 1451/4513/1585 1449/4511/1583 1608/4927/1744 +f 1586/4867/1721 1608/4927/1744 1585/4925/1722 +f 1609/4928/1745 1608/4927/1744 1586/4867/1721 +f 1610/4929/1746 1609/4928/1745 1586/4867/1721 +f 1611/4930/1747 1609/4928/1745 1610/4931/1746 +f 1612/4932/1748 1611/4933/1747 1610/4934/1746 +f 1457/4935/1591 1611/4936/1747 1612/4937/1748 +f 1459/4938/1593 1457/4939/1591 1612/4940/1748 +f 1614/4941/1749 1613/4942/1750 1473/4943/1751 +f 1615/4944/1752 1613/4942/1750 1614/4941/1749 +f 1616/4945/1753 1615/4944/1752 1614/4941/1749 +f 1570/4946/1706 1615/4944/1752 1616/4945/1753 +f 1617/4947/1754 1570/4946/1706 1616/4945/1753 +f 1599/4948/1755 1570/4946/1706 1617/4947/1754 +f 1618/4949/1756 1548/4950/1682 1546/4951/1678 +f 1619/4952/1757 1548/4953/1682 1618/4954/1756 +f 1600/4904/1736 1619/4955/1757 1618/4956/1756 +f 1620/4957/1758 1619/4958/1757 1600/4904/1736 +f 1602/4959/1738 1620/4960/1758 1600/4904/1736 +f 1604/4961/1740 1620/4962/1758 1602/4963/1738 +f 1590/4871/1725 1586/4867/1721 1588/4869/1723 +f 1621/4964/1759 1586/4867/1721 1590/4871/1725 +f 1622/4965/1760 1621/4964/1759 1590/4871/1725 +f 1623/4966/1761 1621/4964/1759 1622/4967/1760 +f 1463/4534/1597 1623/4968/1761 1622/4969/1760 +f 1461/4970/1595 1623/4971/1761 1463/4534/1597 +f 1527/4662/1661 1524/4659/1658 1525/4660/1659 +f 1624/4972/1762 1524/4659/1658 1527/4662/1661 +f 1558/4973/1692 1624/4972/1762 1527/4662/1661 +f 1523/4657/1657 1624/4972/1762 1558/4974/1692 +f 1522/4975/1656 1523/4657/1657 1558/4976/1692 +f 1550/4977/1684 1604/4978/1740 1551/4979/1685 +f 1620/4980/1758 1604/4981/1740 1550/4982/1684 +f 1549/4983/1683 1620/4984/1758 1550/4985/1684 +f 1619/4986/1757 1620/4987/1758 1549/4988/1683 +f 1548/4989/1682 1619/4990/1757 1549/4991/1683 +f 1609/4928/1745 1451/4513/1585 1608/4927/1744 +f 1453/4515/1587 1451/4513/1585 1609/4928/1745 +f 1611/4992/1747 1453/4515/1587 1609/4928/1745 +f 1455/4993/1589 1453/4515/1587 1611/4994/1747 +f 1457/4995/1591 1455/4996/1589 1611/4997/1747 +f 1595/4998/1730 1452/4514/1586 1454/4516/1588 +f 1450/4512/1584 1452/4514/1586 1595/4999/1730 +f 1625/5000/1763 1450/4512/1584 1595/5001/1730 +f 1448/4510/1582 1450/4512/1584 1625/5002/1763 +f 1446/4508/1580 1448/4510/1582 1625/5003/1763 +f 1527/4662/1733 1627/5004/1764 1626/5005/1765 +f 1628/5006/1766 1627/5007/1764 1527/4662/1733 +f 1629/5008/1767 1628/5009/1766 1527/4662/1733 +f 1594/4896/1729 1628/5010/1766 1629/5008/1767 +f 1596/4898/1731 1594/4896/1729 1629/5008/1767 +f 1630/5011/1768 1580/5012/1715 1544/5013/1680 +f 1631/5014/1769 1580/5012/1715 1630/5011/1768 +f 1632/5015/1770 1631/5014/1769 1630/5011/1768 +f 1633/5016/1771 1631/5014/1769 1632/5017/1770 +f 1627/5018/1764 1458/4522/1592 1626/5019/1765 +f 1456/4518/1590 1458/4522/1592 1627/5020/1764 +f 1628/5021/1766 1456/4518/1590 1627/5022/1764 +f 1594/4896/1729 1456/4518/1590 1628/5023/1766 +f 1634/5024/1772 1568/5025/1702 1567/5026/1701 +f 1569/5027/1703 1568/5028/1702 1634/5029/1772 +f 1545/5030/1679 1569/5031/1703 1634/5032/1772 +f 1547/5033/1681 1569/5034/1703 1545/5035/1679 +f 1447/4509/1581 1607/4926/1743 1449/4511/1583 +f 1635/5036/1773 1607/4926/1743 1447/4509/1581 +f 1445/4507/1579 1635/5037/1773 1447/4509/1581 +f 1552/5038/1686 1635/5039/1773 1445/4507/1579 +f 1562/5040/1696 1458/4522/1592 1460/5041/1594 +f 1626/5042/1765 1458/4522/1592 1562/5043/1696 +f 1564/5044/1698 1626/5045/1765 1562/5046/1696 +f 1527/4662/1733 1626/5047/1765 1564/5048/1698 +f 1605/5049/1741 1635/5050/1773 1552/5051/1686 +f 1606/4923/1742 1635/5052/1773 1605/5053/1741 +f 1603/5054/1739 1606/4923/1742 1605/5055/1741 +f 1618/5056/1774 1576/5057/1710 1574/5058/1708 +f 1578/5059/1712 1576/5057/1710 1618/5060/1774 +f 1546/5061/1714 1578/5059/1712 1618/5062/1774 +f 1473/4943/1751 1636/5063/1775 1418/5064/1776 +f 1637/5065/1777 1636/5066/1775 1473/4943/1751 +f 1613/4942/1750 1637/5067/1777 1473/4943/1751 +f 1630/5011/1768 1417/5068/1553 1632/5069/1770 +f 1419/5070/1551 1417/5071/1553 1630/5011/1768 +f 1486/5072/1620 1419/5070/1551 1630/5011/1768 +f 1465/4539/1599 1592/4873/1727 1467/4541/1601 +f 1622/5073/1760 1592/4873/1727 1465/4539/1599 +f 1463/4534/1597 1622/5074/1760 1465/4539/1599 +f 1589/4870/1724 1617/5075/1778 1616/5076/1779 +f 1599/5077/1737 1617/5075/1778 1589/4870/1724 +f 1601/5078/1735 1599/5077/1737 1589/4870/1724 +f 1631/5014/1769 1581/5079/1716 1580/5012/1715 +f 1582/5080/1717 1581/5081/1716 1631/5014/1769 +f 1583/5082/1718 1582/5080/1717 1631/5014/1769 +f 1625/5083/1763 1485/4563/1619 1446/4508/1580 +f 1598/4902/1734 1485/4563/1619 1625/5084/1763 +f 1597/4900/1732 1598/4902/1734 1625/5085/1763 +f 1638/5086/1780 1584/5087/1719 1583/4840/1718 +f 1639/5088/1781 1584/5089/1719 1638/5090/1780 +f 1633/5091/1771 1639/5092/1781 1638/5093/1780 +f 1640/5094/1782 1488/5095/1622 1486/5072/1620 +f 1528/5096/1662 1488/5095/1622 1640/5094/1782 +f 1530/5097/1664 1528/5096/1662 1640/5094/1782 +f 1418/5098/1776 1641/5099/1783 1417/5100/1553 +f 1636/5101/1775 1641/5102/1783 1418/5103/1776 +f 1591/4872/1726 1616/5076/1779 1614/5104/1784 +f 1589/4870/1724 1616/5076/1779 1591/4872/1726 +f 1637/5105/1777 1639/5106/1781 1642/5107/1785 +f 1613/5108/1750 1639/5109/1781 1637/5110/1777 +f 1560/5111/1694 1460/5112/1594 1462/5113/1596 +f 1562/5114/1696 1460/5115/1594 1560/5116/1694 +f 1613/5117/1750 1584/5118/1719 1639/5119/1781 +f 1615/5120/1752 1584/5121/1719 1613/5122/1750 +f 1505/4597/1639 1441/4503/1575 1439/4501/1573 +f 1507/4599/1641 1441/4503/1575 1505/4597/1639 +f 1615/5123/1752 1571/4821/1705 1584/5124/1719 +f 1570/4822/1706 1571/4821/1705 1615/5125/1752 +f 1533/5126/1667 1496/5127/1630 1494/4572/1628 +f 1535/5128/1669 1496/5129/1630 1533/5130/1667 +f 1487/4565/1621 1423/4483/1557 1421/4481/1555 +f 1489/4567/1623 1423/4483/1557 1487/4565/1621 +f 1489/4567/1623 1425/4485/1559 1423/4483/1557 +f 1491/4569/1625 1425/4485/1559 1489/4567/1623 +f 1491/4569/1625 1427/4487/1561 1425/4485/1559 +f 1493/4571/1627 1427/4487/1561 1491/4569/1625 +f 1493/4571/1627 1429/4489/1563 1427/4487/1561 +f 1495/4573/1629 1429/4489/1563 1493/4571/1627 +f 1495/4573/1629 1431/4491/1565 1429/4489/1563 +f 1497/5131/1631 1431/4491/1565 1495/4573/1629 +f 1529/4664/1663 1492/4570/1626 1490/4568/1624 +f 1531/4666/1665 1492/4570/1626 1529/4664/1663 +f 1531/4666/1665 1494/4572/1628 1492/4570/1626 +f 1533/5132/1667 1494/4572/1628 1531/4666/1665 +f 1642/5133/1785 1633/5134/1771 1632/5135/1770 +f 1639/5136/1781 1633/5137/1771 1642/5138/1785 +f 1623/5139/1761 1612/5140/1748 1610/5141/1746 +f 1461/5142/1595 1612/5143/1748 1623/5144/1761 +f 1599/5145/1755 1572/5146/1704 1570/4946/1706 +f 1600/5147/1786 1572/5148/1704 1599/5149/1755 +f 1600/5150/1786 1574/5151/1708 1572/5152/1704 +f 1618/5153/1774 1574/5154/1708 1600/5155/1786 +f 1497/5156/1631 1433/5157/1567 1431/4491/1565 +f 1499/5158/1633 1433/5159/1567 1497/5160/1631 +f 1499/5161/1633 1435/4496/1569 1433/5162/1567 +f 1501/5163/1635 1435/4496/1569 1499/5164/1633 +f 1545/5165/1679 1630/5011/1768 1544/5013/1680 +f 1634/5166/1772 1630/5011/1768 1545/5167/1679 +f 1501/5168/1635 1437/4499/1571 1435/4496/1569 +f 1503/4592/1637 1437/4499/1571 1501/5169/1635 +f 1638/5170/1780 1631/5014/1769 1633/5016/1771 +f 1583/5082/1718 1631/5014/1769 1638/5171/1780 +f 1621/4964/1759 1610/5172/1746 1586/4867/1721 +f 1623/5173/1761 1610/5174/1746 1621/4964/1759 +f 1484/4562/1618 1526/4661/1660 1516/4624/1650 +f 1485/4563/1619 1526/4661/1660 1484/4562/1618 +f 1630/5011/1768 1640/5094/1782 1486/5072/1620 +f 1634/5175/1772 1640/5094/1782 1630/5011/1768 +f 1567/5176/1701 1640/5094/1782 1634/5177/1772 +f 1566/5178/1700 1640/5094/1782 1567/5179/1701 +f 1503/4592/1637 1439/4501/1573 1437/4499/1571 +f 1505/4597/1639 1439/4501/1573 1503/4592/1637 +f 1636/5180/1775 1642/5181/1785 1641/5182/1783 +f 1637/5183/1777 1642/5184/1785 1636/5185/1775 +f 1471/4545/1605 1614/5186/1784 1473/4547/1607 +f 1469/4543/1603 1614/5187/1784 1471/4545/1605 +f 1641/5188/1783 1632/5189/1770 1417/5190/1553 +f 1642/5191/1785 1632/5192/1770 1641/5193/1783 +f 1593/4874/1728 1614/5194/1784 1469/4543/1603 +f 1591/4872/1726 1614/5195/1784 1593/4874/1728 +f 1527/4662/1661 1564/5196/1698 1565/5197/1699 +f 1624/4972/1762 1523/4657/1657 1524/4659/1658 +f 1507/4599/1641 1443/4505/1577 1441/4503/1575 +f 1592/4873/1727 1622/5198/1760 1590/4871/1725 +f 1601/5078/1735 1589/4870/1724 1587/4866/1720 +f 1461/5199/1595 1459/5200/1593 1612/5201/1748 +f 1606/4923/1742 1607/4926/1743 1635/5202/1773 +f 1530/5097/1664 1640/5094/1782 1566/5203/1700 +f 1597/4900/1732 1625/5204/1763 1595/5205/1730 +f 1527/4662/1733 1596/4898/1731 1629/5008/1767 +s 102 +f 1645/5206/1787 1644/5207/1788 1643/5208/1789 +f 1646/5209/1790 1644/5207/1788 1645/5206/1787 +f 1647/5210/1791 1646/5209/1790 1645/5206/1787 +f 1648/5211/1792 1646/5209/1790 1647/5210/1791 +f 1649/5212/1793 1648/5211/1792 1647/5210/1791 +f 1650/5213/1794 1648/5211/1792 1649/5212/1793 +f 1651/5214/1795 1650/5213/1794 1649/5212/1793 +f 1652/5215/1796 1650/5213/1794 1651/5214/1795 +f 1653/5216/1797 1652/5215/1796 1651/5214/1795 +f 1654/5217/1798 1652/5215/1796 1653/5216/1797 +f 1655/5218/1799 1654/5217/1798 1653/5216/1797 +f 1656/5219/1800 1654/5217/1798 1655/5218/1799 +f 1657/5220/1801 1656/5219/1800 1655/5218/1799 +f 1658/5221/1802 1656/5219/1800 1657/5220/1801 +f 1659/5222/1803 1658/5221/1802 1657/5220/1801 +f 1660/5223/1804 1658/5221/1802 1659/5222/1803 +f 1661/5224/1805 1660/5223/1804 1659/5222/1803 +f 1662/5225/1806 1660/5223/1804 1661/5224/1805 +f 1663/5226/1807 1662/5225/1806 1661/5224/1805 +f 1664/5227/1808 1662/5225/1806 1663/5226/1807 +f 1665/5228/1809 1664/5227/1808 1663/5226/1807 +f 1666/5229/1810 1664/5227/1808 1665/5228/1809 +f 1667/5230/1811 1666/5229/1810 1665/5228/1809 +f 1668/5231/1812 1666/5229/1810 1667/5232/1811 +f 1669/5233/1813 1668/5231/1812 1667/5234/1811 +f 1670/5235/1814 1668/5231/1812 1669/5233/1813 +f 1671/5236/1815 1670/5235/1814 1669/5233/1813 +f 1672/5237/1816 1670/5235/1814 1671/5236/1815 +f 1673/5238/1817 1672/5237/1816 1671/5236/1815 +f 1674/5239/1818 1672/5237/1816 1673/5238/1817 +f 1675/5240/1819 1674/5239/1818 1673/5238/1817 +f 1676/5241/1820 1674/5239/1818 1675/5240/1819 +f 1677/5242/1821 1676/5241/1820 1675/5240/1819 +f 1678/5243/1822 1676/5241/1820 1677/5242/1821 +f 1679/5244/1823 1678/5243/1822 1677/5242/1821 +f 1680/5245/1824 1678/5243/1822 1679/5244/1823 +f 1683/5246/1825 1682/5247/1826 1681/5248/1827 +f 1684/5249/1828 1682/5247/1826 1683/5246/1825 +f 1685/5250/1829 1684/5249/1828 1683/5246/1825 +f 1686/5251/1830 1684/5249/1828 1685/5250/1829 +f 1687/5252/1831 1686/5251/1830 1685/5250/1829 +f 1688/5253/1832 1686/5251/1830 1687/5252/1831 +f 1689/5254/1833 1688/5253/1832 1687/5252/1831 +f 1690/5255/1834 1688/5253/1832 1689/5254/1833 +f 1691/5256/1835 1690/5255/1834 1689/5254/1833 +f 1692/5257/1836 1690/5255/1834 1691/5256/1835 +f 1693/5258/1837 1692/5257/1836 1691/5256/1835 +f 1694/5259/1838 1692/5257/1836 1693/5258/1837 +f 1695/5260/1839 1694/5259/1838 1693/5258/1837 +f 1696/5261/1840 1694/5259/1838 1695/5260/1839 +f 1697/5262/1841 1696/5261/1840 1695/5260/1839 +f 1698/5263/1842 1696/5261/1840 1697/5262/1841 +f 1699/5264/1843 1698/5263/1842 1697/5262/1841 +f 1700/5265/1844 1698/5263/1842 1699/5264/1843 +f 1701/5266/1845 1700/5265/1844 1699/5264/1843 +f 1702/5267/1846 1700/5265/1844 1701/5266/1845 +f 1703/5268/1847 1702/5267/1846 1701/5266/1845 +f 1704/5269/1848 1702/5267/1846 1703/5268/1847 +f 1705/5270/1849 1704/5269/1848 1703/5268/1847 +f 1706/5271/1850 1704/5269/1848 1705/5270/1849 +f 1707/5272/1851 1706/5271/1850 1705/5270/1849 +f 1682/5273/1826 1706/5271/1850 1707/5272/1851 +f 1708/5274/1852 1682/5273/1826 1707/5272/1851 +f 1681/5275/1827 1682/5273/1826 1708/5274/1852 +f 1709/5276/1853 1681/5275/1827 1708/5274/1852 +f 1710/5277/1854 1667/5278/1811 1665/5228/1809 +f 1711/5279/1855 1667/5280/1811 1710/5281/1854 +f 1712/5282/1856 1711/5283/1855 1710/5284/1854 +f 1713/5285/1857 1711/5286/1855 1712/5287/1856 +f 1714/5288/1858 1713/5289/1857 1712/5290/1856 +f 1715/5291/1859 1713/5292/1857 1714/5293/1858 +f 1716/5294/1860 1715/5295/1859 1714/5296/1858 +f 1717/5297/1861 1715/5298/1859 1716/5299/1860 +f 1718/5300/1862 1717/5301/1861 1716/5302/1860 +f 1719/5303/1863 1717/5304/1861 1718/5305/1862 +f 1720/5306/1864 1719/5307/1863 1718/5308/1862 +f 1721/5309/1865 1719/5310/1863 1720/5311/1864 +f 1722/5312/1866 1721/5313/1865 1720/5314/1864 +f 1723/5315/1867 1721/5316/1865 1722/5317/1866 +f 1724/5318/1868 1723/5319/1867 1722/5320/1866 +f 1725/5321/1869 1723/5322/1867 1724/5323/1868 +f 1726/5324/1870 1725/5325/1869 1724/5326/1868 +f 1727/5327/1871 1725/5328/1869 1726/5329/1870 +f 1728/5330/1872 1727/5331/1871 1726/5332/1870 +f 1729/5333/1873 1727/5334/1871 1728/5335/1872 +f 1730/5336/1874 1729/5337/1873 1728/5338/1872 +f 1733/5339/1875 1732/5340/1876 1731/5341/1877 +f 1734/5342/1878 1732/5340/1876 1733/5339/1875 +f 1735/5343/1879 1734/5342/1878 1733/5339/1875 +f 1736/5344/1880 1734/5342/1878 1735/5343/1879 +f 1737/5345/1881 1736/5344/1880 1735/5343/1879 +f 1738/5346/1882 1736/5344/1880 1737/5345/1881 +f 1739/5347/1883 1738/5346/1882 1737/5345/1881 +f 1740/5348/1884 1738/5346/1882 1739/5349/1883 +f 1741/5350/1885 1740/5348/1884 1739/5351/1883 +f 1742/5352/1886 1740/5348/1884 1741/5353/1885 +f 1743/5354/1887 1742/5352/1886 1741/5355/1885 +f 1744/5356/1888 1742/5352/1886 1743/5357/1887 +f 1745/5358/1889 1744/5356/1888 1743/5359/1887 +f 1746/5360/1890 1744/5356/1888 1745/5361/1889 +f 1747/5362/1891 1746/5360/1890 1745/5363/1889 +f 1748/5364/1892 1746/5360/1890 1747/5365/1891 +f 1749/5366/1893 1748/5364/1892 1747/5367/1891 +f 1750/5368/1894 1748/5364/1892 1749/5366/1893 +f 1751/5369/1895 1750/5368/1894 1749/5366/1893 +f 1752/5370/1896 1651/5214/1795 1649/5212/1793 +f 1753/5371/1897 1651/5214/1795 1752/5370/1896 +f 1754/5372/1898 1753/5371/1897 1752/5370/1896 +f 1755/5373/1899 1753/5371/1897 1754/5372/1898 +f 1756/5374/1900 1755/5373/1899 1754/5372/1898 +f 1757/5375/1901 1755/5373/1899 1756/5374/1900 +f 1758/5376/1902 1757/5375/1901 1756/5374/1900 +f 1759/5377/1903 1757/5375/1901 1758/5376/1902 +f 1760/5378/1904 1759/5377/1903 1758/5376/1902 +f 1761/5379/1905 1759/5377/1903 1760/5378/1904 +f 1762/5380/1906 1761/5379/1905 1760/5378/1904 +f 1763/5381/1907 1761/5379/1905 1762/5380/1906 +f 1764/5382/1908 1763/5381/1907 1762/5380/1906 +f 1765/5383/1909 1763/5381/1907 1764/5382/1908 +f 1766/5384/1910 1765/5383/1909 1764/5382/1908 +f 1767/5385/1911 1765/5383/1909 1766/5384/1910 +f 1768/5386/1912 1767/5385/1911 1766/5384/1910 +f 1769/5387/1913 1767/5385/1911 1768/5388/1912 +f 1770/5389/1914 1769/5387/1913 1768/5390/1912 +f 1772/5391/1915 1771/5392/1916 1748/5393/1892 +f 1773/5394/1917 1771/5392/1916 1772/5391/1915 +f 1774/5395/1918 1773/5394/1917 1772/5391/1915 +f 1775/5396/1919 1773/5394/1917 1774/5395/1918 +f 1776/5397/1920 1775/5396/1919 1774/5395/1918 +f 1777/5398/1921 1775/5396/1919 1776/5397/1920 +f 1778/5399/1922 1777/5398/1921 1776/5397/1920 +f 1779/5400/1923 1777/5398/1921 1778/5399/1922 +f 1780/5401/1924 1779/5400/1923 1778/5399/1922 +f 1781/5402/1925 1779/5400/1923 1780/5403/1924 +f 1782/5404/1926 1781/5405/1925 1780/5406/1924 +f 1783/5407/1927 1781/5408/1925 1782/5409/1926 +f 1784/5410/1928 1783/5407/1927 1782/5411/1926 +f 1785/5412/1929 1783/5407/1927 1784/5410/1928 +f 1786/5413/1930 1785/5412/1929 1784/5410/1928 +f 1787/5414/1931 1785/5412/1929 1786/5413/1930 +f 1773/5394/1917 1788/5415/1932 1771/5392/1916 +f 1789/5416/1933 1788/5415/1932 1773/5394/1917 +f 1775/5396/1919 1789/5416/1933 1773/5394/1917 +f 1790/5417/1934 1789/5416/1933 1775/5396/1919 +f 1777/5398/1921 1790/5418/1934 1775/5396/1919 +f 1791/5419/1935 1790/5420/1934 1777/5398/1921 +f 1779/5400/1923 1791/5421/1935 1777/5398/1921 +f 1792/5422/1936 1791/5423/1935 1779/5400/1923 +f 1781/5424/1925 1792/5422/1936 1779/5400/1923 +f 1793/5425/1937 1792/5422/1936 1781/5426/1925 +f 1783/5407/1927 1793/5427/1937 1781/5428/1925 +f 1794/5429/1938 1793/5430/1937 1783/5407/1927 +f 1785/5412/1929 1794/5429/1938 1783/5407/1927 +f 1795/5431/1939 1794/5429/1938 1785/5412/1929 +f 1787/5414/1931 1795/5431/1939 1785/5412/1929 +f 1796/5432/1940 1795/5431/1939 1787/5414/1931 +f 1799/5433/1941 1798/5434/1942 1797/5435/1943 +f 1800/5436/1944 1798/5434/1942 1799/5433/1941 +f 1801/5437/1945 1800/5436/1944 1799/5433/1941 +f 1802/5438/1946 1800/5436/1944 1801/5437/1945 +f 1803/5439/1947 1802/5438/1946 1801/5437/1945 +f 1804/5440/1948 1802/5438/1946 1803/5441/1947 +f 1805/5442/1949 1804/5440/1948 1803/5443/1947 +f 1806/5444/1950 1804/5440/1948 1805/5445/1949 +f 1807/5446/1951 1806/5447/1950 1805/5448/1949 +f 1808/5449/1952 1806/5450/1950 1807/5451/1951 +f 1809/5452/1953 1808/5453/1952 1807/5454/1951 +f 1810/5455/1954 1808/5456/1952 1809/5457/1953 +f 1811/5458/1955 1810/5455/1954 1809/5459/1953 +f 1812/5460/1956 1810/5455/1954 1811/5458/1955 +f 1656/5219/1800 1812/5460/1956 1811/5458/1955 +f 1658/5221/1802 1812/5460/1956 1656/5219/1800 +f 1788/5415/1932 1813/5461/1957 1771/5392/1916 +f 1814/5462/1958 1813/5461/1957 1788/5415/1932 +f 1789/5416/1933 1814/5462/1958 1788/5415/1932 +f 1815/5463/1959 1814/5462/1958 1789/5416/1933 +f 1790/5464/1934 1815/5463/1959 1789/5416/1933 +f 1816/5465/1960 1815/5463/1959 1790/5466/1934 +f 1817/5467/1961 1816/5468/1960 1790/5469/1934 +f 1818/5470/1962 1816/5471/1960 1817/5472/1961 +f 1819/5473/1963 1818/5474/1962 1817/5475/1961 +f 1820/5476/1964 1818/5477/1962 1819/5478/1963 +f 1821/5479/1965 1820/5476/1964 1819/5480/1963 +f 1822/5481/1966 1820/5476/1964 1821/5479/1965 +f 1823/5482/1967 1822/5481/1966 1821/5479/1965 +f 1824/5483/1968 1822/5481/1966 1823/5482/1967 +f 1825/5484/1969 1824/5483/1968 1823/5482/1967 +s 107 +f 1828/5485/1970 1827/5486/1971 1826/5487/1972 +f 1829/5488/1973 1827/5486/1971 1828/5485/1970 +f 1830/5489/1974 1829/5488/1973 1828/5485/1970 +f 1831/5490/1975 1829/5488/1973 1830/5489/1974 +f 1832/5491/1976 1831/5490/1975 1830/5489/1974 +f 1833/5492/1977 1831/5490/1975 1832/5491/1976 +f 1834/5493/1978 1833/5492/1977 1832/5491/1976 +f 1835/5494/1979 1833/5492/1977 1834/5493/1978 +f 1836/5495/1980 1835/5494/1979 1834/5493/1978 +f 1837/5496/1981 1835/5494/1979 1836/5495/1980 +f 1838/5497/1982 1837/5496/1981 1836/5495/1980 +f 1839/5498/1983 1837/5496/1981 1838/5497/1982 +f 1840/5499/1984 1839/5498/1983 1838/5497/1982 +f 1841/5500/1985 1839/5498/1983 1840/5499/1984 +f 1842/5501/1986 1841/5500/1985 1840/5499/1984 +s 102 +f 1845/5502/1987 1844/5503/1988 1843/5504/1989 +f 1846/5505/1990 1844/5506/1988 1845/5507/1987 +f 1847/5508/1991 1846/5509/1990 1845/5510/1987 +f 1848/5511/1992 1846/5512/1990 1847/5513/1991 +f 1849/5514/1993 1848/5511/1992 1847/5515/1991 +f 1850/5516/1994 1848/5511/1992 1849/5517/1993 +f 1851/5518/1995 1850/5516/1994 1849/5519/1993 +f 1852/5520/1996 1850/5516/1994 1851/5521/1995 +f 1853/5522/1997 1852/5523/1996 1851/5524/1995 +f 1854/5525/1998 1852/5526/1996 1853/5522/1997 +f 1855/5527/1999 1854/5528/1998 1853/5522/1997 +f 1856/5529/2000 1854/5530/1998 1855/5531/1999 +f 1857/5532/2001 1856/5533/2000 1855/5534/1999 +f 1858/5535/2002 1856/5536/2000 1857/5537/2001 +f 1859/5538/2003 1858/5535/2002 1857/5539/2001 +f 1860/5540/2004 1847/5541/1991 1845/5542/1987 +f 1861/5543/2005 1847/5544/1991 1860/5545/2004 +f 1862/5546/2006 1861/5547/2005 1860/5548/2004 +f 1863/5549/2007 1861/5550/2005 1862/5551/2006 +f 1864/5552/2008 1863/5549/2007 1862/5553/2006 +f 1865/5554/2009 1863/5549/2007 1864/5552/2008 +f 1866/5555/2010 1865/5556/2009 1864/5552/2008 +f 1851/5557/1995 1865/5558/2009 1866/5559/2010 +f 1867/5560/2011 1851/5561/1995 1866/5562/2010 +f 1868/5563/2012 1851/5564/1995 1867/5565/2011 +f 1869/5566/2013 1868/5567/2012 1867/5568/2011 +f 1859/5569/2003 1868/5570/2012 1869/5571/2013 +f 1871/5572/2014 1825/5573/1969 1870/5574/2015 +f 1872/5575/2016 1825/5573/1969 1871/5572/2014 +f 1873/5576/2017 1872/5575/2016 1871/5572/2014 +f 1874/5577/2018 1872/5575/2016 1873/5576/2017 +f 1875/5578/2019 1874/5577/2018 1873/5576/2017 +f 1876/5579/2020 1874/5577/2018 1875/5578/2019 +f 1877/5580/2021 1876/5579/2020 1875/5578/2019 +f 1878/5581/2022 1876/5579/2020 1877/5580/2021 +f 1879/5582/2023 1878/5581/2022 1877/5580/2021 +f 1880/5583/2024 1878/5581/2022 1879/5582/2023 +f 1881/5584/2025 1880/5585/2024 1879/5582/2023 +f 1882/5586/2026 1880/5587/2024 1881/5584/2025 +f 1883/5588/2027 1746/5360/1890 1748/5364/1892 +f 1884/5589/2028 1746/5360/1890 1883/5590/2027 +f 1885/5591/2029 1884/5589/2028 1883/5592/2027 +f 1886/5593/2030 1884/5589/2028 1885/5591/2029 +f 1887/5594/2031 1886/5593/2030 1885/5591/2029 +f 1888/5595/2032 1886/5593/2030 1887/5594/2031 +f 1815/5596/1959 1888/5595/2032 1887/5594/2031 +f 1889/5597/2033 1888/5595/2032 1815/5596/1959 +f 1816/5598/1960 1889/5597/2033 1815/5596/1959 +f 1890/5599/2034 1889/5597/2033 1816/5598/1960 +f 1818/5600/1962 1890/5599/2034 1816/5598/1960 +f 1732/5340/1876 1890/5599/2034 1818/5600/1962 +f 1791/5601/1935 1817/5602/1961 1790/5603/1934 +f 1891/5604/2035 1817/5605/1961 1791/5606/1935 +f 1792/5422/1936 1891/5607/2035 1791/5608/1935 +f 1823/5482/1967 1891/5609/2035 1792/5422/1936 +f 1793/5610/1937 1823/5482/1967 1792/5422/1936 +f 1892/5611/2036 1823/5482/1967 1793/5612/1937 +f 1794/5429/1938 1892/5613/2036 1793/5614/1937 +f 1893/5615/2037 1892/5616/2036 1794/5429/1938 +f 1795/5431/1939 1893/5617/2037 1794/5429/1938 +f 1894/5618/2038 1893/5619/2037 1795/5431/1939 +f 1796/5432/1940 1894/5620/2038 1795/5431/1939 +f 1895/5621/2039 1894/5622/2038 1796/5432/1940 +s 107 +f 1897/5623/2040 1896/5624/2041 1826/5487/1972 +f 1898/5625/2042 1896/5624/2041 1897/5623/2040 +f 1899/5626/2043 1898/5625/2042 1897/5623/2040 +f 1900/5627/2044 1898/5625/2042 1899/5626/2043 +f 1901/5628/2045 1900/5627/2044 1899/5626/2043 +f 1902/5629/2046 1900/5627/2044 1901/5628/2045 +f 1903/5630/2047 1902/5629/2046 1901/5628/2045 +f 1842/5501/1986 1902/5629/2046 1903/5630/2047 +f 1904/5631/2048 1842/5501/1986 1903/5630/2047 +f 1841/5500/1985 1842/5501/1986 1904/5631/2048 +f 1905/5632/2049 1841/5500/1985 1904/5631/2048 +f 1839/5498/1983 1841/5500/1985 1905/5632/2049 +f 1906/5633/2050 1828/5485/1970 1826/5487/1972 +f 1830/5489/1974 1828/5485/1970 1906/5633/2050 +f 1907/5634/2051 1830/5489/1974 1906/5633/2050 +f 1832/5491/1976 1830/5489/1974 1907/5634/2051 +f 1908/5635/2052 1832/5491/1976 1907/5634/2051 +f 1834/5493/1978 1832/5491/1976 1908/5635/2052 +f 1909/5636/2053 1834/5493/1978 1908/5635/2052 +f 1836/5495/1980 1834/5493/1978 1909/5636/2053 +f 1910/5637/2054 1836/5495/1980 1909/5636/2053 +f 1838/5497/1982 1836/5495/1980 1910/5637/2054 +f 1840/5499/1984 1838/5497/1982 1910/5637/2054 +s 102 +f 1912/5638/2055 1709/5639/1853 1911/5640/2056 +f 1913/5641/2057 1709/5639/1853 1912/5638/2055 +f 1809/5642/1953 1913/5643/2057 1912/5638/2055 +f 1914/5644/2058 1913/5645/2057 1809/5646/1953 +f 1807/5647/1951 1914/5648/2058 1809/5649/1953 +f 1915/5650/2059 1914/5651/2058 1807/5652/1951 +f 1805/5653/1949 1915/5650/2059 1807/5654/1951 +f 1916/5655/2060 1915/5650/2059 1805/5656/1949 +f 1917/5657/2061 1916/5658/2060 1805/5659/1949 +f 1918/5660/2062 1916/5661/2060 1917/5662/2061 +f 1919/5663/2063 1918/5660/2062 1917/5664/2061 +s 107 +f 1896/5624/2041 1906/5633/2050 1826/5487/1972 +f 1907/5634/2051 1906/5633/2050 1896/5624/2041 +f 1898/5625/2042 1907/5634/2051 1896/5624/2041 +f 1908/5635/2052 1907/5634/2051 1898/5625/2042 +f 1900/5627/2044 1908/5635/2052 1898/5625/2042 +f 1909/5636/2053 1908/5635/2052 1900/5627/2044 +f 1902/5629/2046 1909/5636/2053 1900/5627/2044 +f 1910/5637/2054 1909/5636/2053 1902/5629/2046 +f 1842/5501/1986 1910/5637/2054 1902/5629/2046 +f 1840/5499/1984 1910/5637/2054 1842/5501/1986 +s 102 +f 1921/5665/2064 1643/5208/1789 1920/5666/2065 +f 1645/5206/1787 1643/5208/1789 1921/5665/2064 +f 1922/5667/2066 1645/5206/1787 1921/5665/2064 +f 1647/5210/1791 1645/5206/1787 1922/5667/2066 +f 1923/5668/2067 1647/5210/1791 1922/5667/2066 +f 1924/5669/2068 1647/5210/1791 1923/5668/2067 +f 1925/5670/2069 1924/5669/2068 1923/5668/2067 +f 1926/5671/2070 1924/5669/2068 1925/5670/2069 +f 1927/5672/2071 1926/5671/2070 1925/5670/2069 +f 1928/5673/2072 1926/5671/2070 1927/5672/2071 +f 1802/5438/1946 1929/5674/2073 1800/5436/1944 +f 1930/5675/2074 1929/5676/2073 1802/5438/1946 +f 1804/5440/1948 1930/5675/2074 1802/5438/1946 +f 1931/5677/2075 1930/5675/2074 1804/5440/1948 +f 1806/5678/1950 1931/5679/2075 1804/5440/1948 +f 1932/5680/2076 1931/5681/2075 1806/5682/1950 +f 1808/5683/1952 1932/5684/2076 1806/5685/1950 +f 1933/5686/2077 1932/5687/2076 1808/5688/1952 +f 1810/5455/1954 1933/5686/2077 1808/5689/1952 +f 1812/5460/1956 1933/5686/2077 1810/5455/1954 +f 1935/5690/2078 1895/5691/2039 1934/5692/2079 +f 1936/5693/2080 1895/5691/2039 1935/5690/2078 +f 1937/5694/2081 1936/5693/2080 1935/5690/2078 +f 1938/5695/2082 1936/5693/2080 1937/5694/2081 +f 1939/5696/2083 1938/5695/2082 1937/5694/2081 +f 1871/5572/2014 1938/5695/2082 1939/5696/2083 +f 1940/5697/2084 1871/5572/2014 1939/5696/2083 +f 1873/5576/2017 1871/5572/2014 1940/5697/2084 +f 1941/5698/2085 1873/5576/2017 1940/5697/2084 +f 1942/5699/2086 1873/5576/2017 1941/5698/2085 +f 1943/5700/2087 1858/5535/2002 1859/5701/2003 +f 1944/5702/2088 1858/5535/2002 1943/5700/2087 +f 1945/5703/2089 1944/5702/2088 1943/5700/2087 +f 1946/5704/2090 1944/5702/2088 1945/5703/2089 +f 1947/5705/2091 1946/5704/2090 1945/5703/2089 +f 1948/5706/2092 1946/5704/2090 1947/5705/2091 +f 1949/5707/2093 1948/5708/2092 1947/5705/2091 +f 1950/5709/2094 1948/5710/2092 1949/5711/2093 +f 1846/5712/1990 1950/5713/2094 1949/5714/2093 +f 1848/5511/1992 1950/5715/2094 1846/5716/1990 +f 1951/5717/2095 1749/5366/1893 1747/5718/1891 +f 1952/5719/2096 1749/5366/1893 1951/5720/2095 +f 1953/5721/2097 1952/5722/2096 1951/5723/2095 +f 1954/5724/2098 1952/5725/2096 1953/5726/2097 +f 1955/5727/2099 1954/5728/2098 1953/5729/2097 +f 1956/5730/2100 1954/5731/2098 1955/5732/2099 +f 1957/5733/2101 1956/5734/2100 1955/5735/2099 +f 1786/5736/1930 1956/5737/2100 1957/5738/2101 +f 1958/5739/2102 1786/5740/1930 1957/5741/2101 +s 113 +f 1961/5742/2103 1960/5743/2104 1959/5744/2105 +f 1962/5745/2106 1960/5746/2104 1961/5747/2103 +f 1963/5748/2107 1962/5749/2106 1961/5750/2103 +f 1964/5751/2108 1962/5752/2106 1963/5753/2107 +f 1965/5754/2109 1964/5755/2108 1963/5756/2107 +f 1966/5757/2110 1964/5758/2108 1965/5759/2109 +f 1967/5760/2111 1966/5761/2110 1965/5762/2109 +f 1968/5763/2112 1966/5764/2110 1967/5765/2111 +s 102 +f 1971/5766/2113 1970/5767/2114 1969/5768/2115 +f 1972/5769/2116 1970/5767/2114 1971/5770/2113 +f 1973/5771/2117 1972/5772/2116 1971/5773/2113 +f 1974/5774/2118 1972/5775/2116 1973/5776/2117 +f 1975/5777/2119 1974/5778/2118 1973/5779/2117 +f 1976/5780/2120 1974/5781/2118 1975/5782/2119 +f 1977/5783/2121 1976/5784/2120 1975/5785/2119 +f 1733/5786/1875 1976/5787/2120 1977/5788/2121 +f 1673/5238/1817 1978/5789/2122 1675/5240/1819 +f 1979/5790/2123 1978/5791/2122 1673/5238/1817 +f 1980/5792/2124 1979/5793/2123 1673/5238/1817 +f 1981/5794/2125 1979/5795/2123 1980/5796/2124 +f 1982/5797/2126 1981/5798/2125 1980/5799/2124 +f 1711/5800/1855 1981/5801/2125 1982/5802/2126 +f 1669/5233/1813 1711/5803/1855 1982/5804/2126 +f 1667/5805/1811 1711/5806/1855 1669/5233/1813 +f 1784/5410/1928 1956/5807/2100 1786/5413/1930 +f 1983/5808/2127 1956/5809/2100 1784/5410/1928 +f 1984/5810/2128 1983/5811/2127 1784/5410/1928 +f 1985/5812/2129 1983/5813/2127 1984/5814/2128 +f 1986/5815/2130 1985/5816/2129 1984/5817/2128 +f 1987/5818/2131 1985/5819/2129 1986/5820/2130 +f 1774/5395/1918 1987/5821/2131 1986/5822/2130 +f 1772/5391/1915 1987/5823/2131 1774/5395/1918 +f 1989/5824/2132 1978/5825/2122 1988/5826/2133 +f 1675/5240/1819 1978/5827/2122 1989/5828/2132 +f 1990/5829/2134 1675/5240/1819 1989/5830/2132 +f 1677/5242/1821 1675/5240/1819 1990/5829/2134 +f 1843/5831/1989 1677/5242/1821 1990/5829/2134 +f 1679/5244/1823 1677/5242/1821 1843/5831/1989 +f 1991/5832/2135 1679/5244/1823 1843/5831/1989 +f 1680/5245/1824 1679/5244/1823 1991/5832/2135 +f 1716/5833/1860 1720/5834/1864 1718/5835/1862 +f 1992/5836/2136 1720/5837/1864 1716/5838/1860 +f 1993/5839/2137 1992/5836/2136 1716/5840/1860 +f 1975/5841/2119 1992/5836/2136 1993/5839/2137 +f 1994/5842/2138 1975/5843/2119 1993/5839/2137 +f 1977/5844/2121 1975/5845/2119 1994/5846/2138 +f 1735/5847/1879 1977/5848/2121 1994/5849/2138 +f 1733/5786/1875 1977/5850/2121 1735/5851/1879 +f 1930/5675/2074 1668/5231/1812 1929/5852/2073 +f 1666/5229/1810 1668/5231/1812 1930/5675/2074 +f 1931/5853/2075 1666/5229/1810 1930/5675/2074 +f 1664/5227/1808 1666/5229/1810 1931/5854/2075 +f 1932/5855/2076 1664/5227/1808 1931/5856/2075 +f 1662/5225/1806 1664/5227/1808 1932/5857/2076 +f 1933/5686/2077 1662/5225/1806 1932/5858/2076 +f 1812/5460/1956 1662/5225/1806 1933/5686/2077 +f 1995/5859/2139 1916/5860/2060 1918/5660/2062 +f 1996/5861/2140 1916/5862/2060 1995/5859/2139 +f 1997/5863/2141 1996/5861/2140 1995/5859/2139 +f 1998/5864/2142 1996/5861/2140 1997/5865/2141 +f 1999/5866/2143 1998/5867/2142 1997/5868/2141 +f 1913/5869/2057 1998/5870/2142 1999/5871/2143 +f 1681/5872/1827 1913/5873/2057 1999/5874/2143 +f 1709/5639/1853 1913/5875/2057 1681/5876/1827 +s 113 +f 2002/5877/2144 2001/5878/2145 2000/5879/2146 +f 2003/5880/2147 2001/5881/2145 2002/5882/2144 +f 2004/5883/2148 2003/5884/2147 2002/5885/2144 +f 2005/5886/2149 2003/5887/2147 2004/5888/2148 +f 2006/5889/2150 2005/5890/2149 2004/5891/2148 +f 2007/5892/2151 2005/5893/2149 2006/5894/2150 +f 2008/5895/2152 2007/5896/2151 2006/5897/2150 +f 2009/5898/2153 2007/5899/2151 2008/5900/2152 +f 1962/5901/2106 2000/5902/2146 1960/5903/2104 +f 2002/5904/2144 2000/5905/2146 1962/5906/2106 +f 1964/5907/2108 2002/5908/2144 1962/5909/2106 +f 2004/5910/2148 2002/5911/2144 1964/5912/2108 +f 1966/5913/2110 2004/5914/2148 1964/5915/2108 +f 2006/5916/2150 2004/5917/2148 1966/5918/2110 +f 1968/5919/2112 2006/5920/2150 1966/5921/2110 +f 2008/5922/2152 2006/5923/2150 1968/5924/2112 +s 102 +f 2012/5925/2154 2011/5926/2155 2010/5927/2156 +f 2013/5928/2157 2011/5929/2155 2012/5930/2154 +f 2014/5931/2158 2013/5932/2157 2012/5933/2154 +f 2015/5934/2159 2013/5935/2157 2014/5931/2158 +f 2016/5936/2160 2015/5937/2159 2014/5931/2158 +f 2017/5938/2161 2015/5939/2159 2016/5936/2160 +f 2018/5940/2162 2017/5941/2161 2016/5936/2160 +f 2019/5942/2163 2017/5943/2161 2018/5940/2162 +f 1796/5944/1940 2020/5945/2164 1895/5946/2039 +f 2021/5947/2165 2020/5948/2164 1796/5949/1940 +f 1958/5950/2102 2021/5951/2165 1796/5952/1940 +f 2022/5953/2166 2021/5954/2165 1958/5955/2102 +f 2023/5956/2167 2022/5957/2166 1958/5958/2102 +f 1739/5959/1883 2022/5960/2166 2023/5956/2167 +f 1741/5961/1885 1739/5962/1883 2023/5956/2167 +s 117 +f 2026/5963/2168 2025/5964/2169 2024/5965/2170 +f 2027/5966/2171 2025/5964/2169 2026/5963/2168 +f 2028/5967/2172 2027/5966/2171 2026/5963/2168 +f 2029/5968/2173 2027/5966/2171 2028/5967/2172 +f 2030/5969/2174 2029/5968/2173 2028/5967/2172 +f 2031/5970/2175 2029/5968/2173 2030/5969/2174 +f 2032/5971/2176 2031/5972/2175 2030/5969/2174 +s 102 +f 2016/5936/2160 2033/5973/2177 1882/5586/2026 +f 2034/5974/2178 2033/5973/2177 2016/5936/2160 +f 2014/5931/2158 2034/5974/2178 2016/5936/2160 +f 2035/5975/2179 2034/5974/2178 2014/5931/2158 +f 2012/5976/2154 2035/5975/2179 2014/5931/2158 +f 2036/5977/2180 2035/5975/2179 2012/5978/2154 +f 2010/5979/2156 2036/5977/2180 2012/5980/2154 +f 2037/5981/2181 1678/5243/1822 1680/5245/1824 +f 2038/5982/2182 1678/5243/1822 2037/5983/2181 +f 1797/5435/1943 2038/5984/2182 2037/5985/2181 +f 2039/5986/2183 2038/5987/2182 1797/5435/1943 +f 1798/5434/1942 2039/5988/2183 1797/5435/1943 +f 1672/5237/1816 2039/5989/2183 1798/5434/1942 +f 1670/5235/1814 1672/5237/1816 1798/5434/1942 +s 113 +f 2003/5990/2147 2040/5991/2184 2001/5992/2145 +f 2041/5993/2185 2040/5994/2184 2003/5995/2147 +f 2005/5996/2149 2041/5997/2185 2003/5998/2147 +f 2042/5999/2186 2041/6000/2185 2005/6001/2149 +f 2007/6002/2151 2042/6003/2186 2005/6004/2149 +f 2009/6005/2153 2042/6006/2186 2007/6007/2151 +s 102 +f 1880/6008/2024 1876/5579/2020 1878/5581/2022 +f 2043/6009/2187 1876/5579/2020 1880/6010/2024 +f 2044/6011/2188 2043/6012/2187 1880/6013/2024 +f 2045/6014/2189 2043/6015/2187 2044/6016/2188 +f 2046/6017/2190 2045/6018/2189 2044/6019/2188 +f 2047/6020/2191 2045/6021/2189 2046/6022/2190 +s 113 +f 1965/6023/2109 2048/6024/2192 1967/6025/2111 +f 2049/6026/2193 2048/6027/2192 1965/6028/2109 +f 1963/6029/2107 2049/6030/2193 1965/6031/2109 +f 2050/6032/2194 2049/6033/2193 1963/6034/2107 +f 1961/6035/2103 2050/6036/2194 1963/6037/2107 +f 1959/6038/2105 2050/6039/2194 1961/6040/2103 +s 102 +f 2052/6041/2195 2051/6042/2196 1697/6043/1841 +f 2053/6044/2197 2051/6045/2196 2052/6046/2195 +f 1693/5258/1837 2053/6047/2197 2052/6048/2195 +f 2054/6049/2198 2053/6050/2197 1693/5258/1837 +f 1691/5256/1835 2054/6051/2198 1693/5258/1837 +f 1689/5254/1833 2054/6052/2198 1691/5256/1835 +f 1912/5638/2055 1811/5458/1955 1809/6053/1953 +f 1654/5217/1798 1811/5458/1955 1912/5638/2055 +f 1911/6054/2056 1654/5217/1798 1912/5638/2055 +f 2055/6055/2199 1654/5217/1798 1911/6054/2056 +f 1709/6056/1853 2055/6055/2199 1911/6054/2056 +f 2056/6057/2200 2055/6055/2199 1709/6056/1853 +f 1924/5669/2068 1649/5212/1793 1647/5210/1791 +f 1752/5370/1896 1649/5212/1793 1924/5669/2068 +f 1926/5671/2070 1752/5370/1896 1924/5669/2068 +f 1754/5372/1898 1752/5370/1896 1926/5671/2070 +f 1928/5673/2072 1754/5372/1898 1926/5671/2070 +f 2057/6058/2201 1754/5372/1898 1928/5673/2072 +f 2058/6059/2202 1797/5435/1943 2037/6060/2181 +f 1799/5433/1941 1797/5435/1943 2058/6061/2202 +f 2059/6062/2203 1799/5433/1941 2058/6063/2202 +f 2060/6064/2204 1799/5433/1941 2059/6065/2203 +f 1919/5663/2063 2060/6064/2204 2059/6066/2203 +f 1917/6067/2061 2060/6064/2204 1919/5663/2063 +f 2011/6068/2155 1969/6069/2115 2010/6070/2156 +f 1971/6071/2113 1969/6072/2115 2011/6073/2155 +f 2061/6074/2205 1971/6075/2113 2011/6076/2155 +f 2062/6077/2206 1971/6078/2113 2061/6079/2205 +f 1722/6080/1866 2062/6081/2206 2061/6082/2205 +f 1720/6083/1864 2062/6084/2206 1722/6085/1866 +f 1745/6086/1889 1951/6087/2095 1747/6088/1891 +f 1953/6089/2097 1951/6090/2095 1745/6091/1889 +f 1743/6092/1887 1953/6093/2097 1745/6094/1889 +f 2063/6095/2207 1953/6096/2097 1743/6097/1887 +f 1741/6098/1885 2063/6095/2207 1743/6099/1887 +f 2023/5956/2167 2063/6095/2207 1741/6100/1885 +f 2064/6101/2208 1825/5573/1969 1872/5575/2016 +f 1824/6102/1968 1825/5573/1969 2064/6103/2208 +f 2065/6104/2209 1824/6105/1968 2064/6106/2208 +f 1822/6107/1966 1824/6108/1968 2065/6109/2209 +f 2066/6110/2210 1822/6111/1966 2065/6112/2209 +f 2067/6113/2211 1822/6114/1966 2066/6115/2210 +f 1986/6116/2130 1776/5397/1920 1774/5395/1918 +f 2068/6117/2212 1776/5397/1920 1986/6118/2130 +f 1984/6119/2128 2068/6120/2212 1986/6121/2130 +f 1782/6122/1926 2068/6123/2212 1984/6124/2128 +f 1784/5410/1928 1782/6125/1926 1984/6126/2128 +f 1753/5371/1897 1653/5216/1797 1651/5214/1795 +f 2069/6127/2213 1653/5216/1797 1753/5371/1897 +f 1755/5373/1899 2069/6128/2213 1753/5371/1897 +f 1759/5377/1903 2069/6129/2213 1755/5373/1899 +f 1757/5375/1901 1759/5377/1903 1755/5373/1899 +f 1768/6130/1912 2070/6131/2214 1770/5389/1914 +f 2071/6132/2215 2070/6131/2214 1768/6133/1912 +f 2072/6134/2216 2071/6135/2215 1768/6136/1912 +f 1735/6137/1879 2071/6138/2215 2072/6139/2216 +f 2073/6140/2217 1735/6141/1879 2072/6142/2216 +f 2076/6143/2218 2075/6144/2219 2074/6145/2220 +f 2077/6146/2221 2075/6147/2219 2076/6148/2218 +f 1921/5665/2064 2077/6149/2221 2076/6150/2218 +f 2078/6151/2222 2077/6152/2221 1921/5665/2064 +f 1920/5666/2065 2078/6153/2222 1921/5665/2064 +f 2015/6154/2159 1726/6155/1870 2013/6156/2157 +f 1728/6157/1872 1726/6158/1870 2015/6159/2159 +f 2017/6160/2161 1728/6161/1872 2015/6162/2159 +f 1730/6163/1874 1728/6164/1872 2017/6165/2161 +f 2079/6166/2223 1730/6167/1874 2017/6168/2161 +f 1717/6169/1861 1981/6170/2125 1715/6171/1859 +f 1979/6172/2123 1981/6173/2125 1717/6174/1861 +f 1719/6175/1863 1979/6176/2123 1717/6177/1861 +f 1978/6178/2122 1979/6179/2123 1719/6180/1863 +f 1988/6181/2133 1978/6182/2122 1719/6183/1863 +f 1994/6184/2138 2071/6185/2215 1735/6186/1879 +f 2080/6187/2224 2071/6188/2215 1994/6189/2138 +f 1993/5839/2137 2080/6187/2224 1994/6190/2138 +f 1714/6191/1858 2080/6187/2224 1993/5839/2137 +f 1716/6192/1860 1714/6193/1858 1993/5839/2137 +f 2081/6194/2225 1738/5346/1882 1740/5348/1884 +f 1736/5344/1880 1738/5346/1882 2081/6195/2225 +f 1890/5599/2034 1736/5344/1880 2081/6196/2225 +f 1734/5342/1878 1736/5344/1880 1890/5599/2034 +f 1732/5340/1876 1734/5342/1878 1890/5599/2034 +f 1886/5593/2030 1742/5352/1886 1744/5356/1888 +f 2082/6197/2226 1742/5352/1886 1886/5593/2030 +f 1888/5595/2032 2082/6198/2226 1886/5593/2030 +f 1889/5597/2033 2082/6199/2226 1888/5595/2032 +f 2076/6200/2218 1922/5667/2066 1921/5665/2064 +f 2083/6201/2227 1922/5667/2066 2076/6202/2218 +f 2084/6203/2228 2083/6204/2227 2076/6205/2218 +f 2085/6206/2229 2083/6207/2227 2084/6208/2228 +f 2073/6209/2217 1737/5345/1881 1735/5343/1879 +f 2086/6210/2230 1737/5345/1881 2073/6209/2217 +f 1762/6211/1906 2086/6212/2230 2073/6209/2217 +f 2022/6213/2166 2086/6214/2230 1762/6215/1906 +f 2082/6216/2226 1740/5348/1884 1742/5352/1886 +f 2081/6217/2225 1740/5348/1884 2082/6218/2226 +f 1889/5597/2033 2081/6219/2225 2082/6220/2226 +f 1890/5599/2034 2081/6221/2225 1889/5597/2033 +f 2087/6222/2231 1687/5252/1831 1685/5250/1829 +f 2088/6223/2232 1687/5252/1831 2087/6222/2231 +f 2089/6224/2233 2088/6225/2232 2087/6222/2231 +f 2054/6226/2198 2088/6227/2232 2089/6228/2233 +f 2090/6229/2234 1947/5705/2091 1945/5703/2089 +f 1949/6230/2093 1947/5705/2091 2090/6231/2234 +f 1844/6232/1988 1949/6233/2093 2090/6234/2234 +f 1846/6235/1990 1949/6236/2093 1844/6237/1988 +f 2056/6238/2200 1701/5266/1845 1699/5264/1843 +f 2091/6239/2235 1701/5266/1845 2056/6238/2200 +f 1709/5276/1853 2091/6240/2235 2056/6238/2200 +f 1708/5274/1852 2091/6241/2235 1709/5276/1853 +f 1952/6242/2096 1751/5369/1895 1749/5366/1893 +f 2092/6243/2236 1751/5369/1895 1952/6244/2096 +f 1954/6245/2098 2092/6243/2236 1952/6246/2096 +f 1956/6247/2100 2092/6243/2236 1954/6248/2098 +f 2063/6095/2207 1955/6249/2099 1953/6250/2097 +f 1957/6251/2101 1955/6252/2099 2063/6095/2207 +f 2023/5956/2167 1957/6253/2101 2063/6095/2207 +f 1958/6254/2102 1957/6255/2101 2023/5956/2167 +f 2093/6256/2237 1761/5379/1905 1763/5381/1907 +f 2094/6257/2238 1761/5379/1905 2093/6258/2237 +f 1659/5222/1803 2094/6259/2238 2093/6260/2237 +f 1657/5220/1801 2094/6261/2238 1659/5222/1803 +f 1766/5384/1910 2072/6262/2216 1768/6263/1912 +f 2073/6140/2217 2072/6264/2216 1766/5384/1910 +f 1764/5382/1908 2073/6140/2217 1766/5384/1910 +f 1762/5380/1906 2073/6140/2217 1764/5382/1908 +f 2095/6265/2239 1690/5255/1834 1702/5267/1846 +f 1688/5253/1832 1690/5255/1834 2095/6266/2239 +f 2096/6267/2240 1688/5253/1832 2095/6268/2239 +f 1686/5251/1830 1688/5253/1832 2096/6269/2240 +s 113 +f 2049/6270/2193 2097/6271/2241 2048/6272/2192 +f 2098/6273/2242 2097/6274/2241 2049/6275/2193 +f 2050/6276/2194 2098/6277/2242 2049/6278/2193 +f 1959/6279/2105 2098/6280/2242 2050/6281/2194 +s 102 +f 1868/6282/2012 1853/5522/1997 1851/6283/1995 +f 2099/6284/2243 1853/5522/1997 1868/6285/2012 +f 1859/6286/2003 2099/6287/2243 1868/6288/2012 +f 1857/6289/2001 2099/6290/2243 1859/6291/2003 +f 1849/6292/1993 1865/6293/2009 1851/6294/1995 +f 2100/6295/2244 1865/6296/2009 1849/6297/1993 +f 1847/6298/1991 2100/6299/2244 1849/6300/1993 +f 1861/6301/2005 2100/6302/2244 1847/6303/1991 +f 1852/6304/1996 1948/6305/2092 1950/6306/2094 +f 2101/6307/2245 1948/6308/2092 1852/6309/1996 +f 1854/6310/1998 2101/6311/2245 1852/6312/1996 +f 1856/6313/2000 2101/6314/2245 1854/6315/1998 +f 2045/6316/2189 1872/5575/2016 1874/5577/2018 +f 2064/6317/2208 1872/5575/2016 2045/6318/2189 +f 2047/6319/2191 2064/6320/2208 2045/6321/2189 +f 2102/6322/2246 2064/6323/2208 2047/6324/2191 +s 113 +f 2041/6325/2185 2103/6326/2247 2040/6327/2184 +f 2104/6328/2248 2103/6329/2247 2041/6330/2185 +f 2042/6331/2186 2104/6332/2248 2041/6333/2185 +f 2009/6334/2153 2104/6335/2248 2042/6336/2186 +s 102 +f 1942/5699/2086 1875/5578/2019 1873/5576/2017 +f 1877/5580/2021 1875/5578/2019 1942/5699/2086 +f 2105/6337/2249 1877/5580/2021 1942/5699/2086 +f 2074/6338/2220 1877/5580/2021 2105/6339/2249 +f 2106/6340/2250 1997/6341/2141 1995/5859/2139 +f 2107/6342/2251 1997/6343/2141 2106/6344/2250 +f 2108/6345/2252 2107/6346/2251 2106/6347/2250 +f 1683/6348/1825 2107/6349/2251 2108/6350/2252 +f 2110/6351/2253 1665/5228/1809 2109/6352/2254 +f 1710/6353/1854 1665/5228/1809 2110/6351/2253 +f 2111/6354/2255 1710/6355/1854 2110/6351/2253 +f 1712/6356/1856 1710/6357/1854 2111/6354/2255 +f 1704/5269/1848 2095/6358/2239 1702/5267/1846 +f 2096/6359/2240 2095/6360/2239 1704/5269/1848 +f 1706/5271/1850 2096/6361/2240 1704/5269/1848 +f 1686/5251/1830 2096/6362/2240 1706/5271/1850 +s 117 +f 2114/6363/2256 2113/6364/2257 2112/6365/2258 +f 2115/6366/2259 2113/6367/2257 2114/6368/2256 +f 2116/6369/2260 2115/6370/2259 2114/6371/2256 +f 2117/6372/2261 2115/6373/2259 2116/6374/2260 +f 2115/6375/2259 2118/6376/2262 2113/6377/2257 +f 2119/6378/2263 2118/6379/2262 2115/6380/2259 +f 2117/6381/2261 2119/6382/2263 2115/6383/2259 +f 2120/6384/2264 2119/6385/2263 2117/6386/2261 +f 2027/5966/2171 2121/6387/2265 2025/5964/2169 +f 2122/6388/2266 2121/6389/2265 2027/5966/2171 +f 2029/5968/2173 2122/6390/2266 2027/5966/2171 +f 2031/6391/2175 2122/6392/2266 2029/5968/2173 +s 102 +f 1750/6393/1894 1985/6394/2129 1987/6395/2131 +f 2123/6396/2267 1985/6397/2129 1750/6398/1894 +f 1751/6399/1895 2123/6400/2267 1750/6401/1894 +f 2092/6402/2236 2123/6403/2267 1751/6404/1895 +f 1702/5267/1846 1698/5263/1842 1700/5265/1844 +f 2124/6405/2268 1698/5263/1842 1702/5267/1846 +f 1690/5255/1834 2124/6406/2268 1702/5267/1846 +f 1692/5257/1836 2124/6407/2268 1690/5255/1834 +f 2091/6408/2235 1703/5268/1847 1701/5266/1845 +f 2125/6409/2269 1703/5268/1847 2091/6410/2235 +f 1708/5274/1852 2125/6411/2269 2091/6412/2235 +f 1707/5272/1851 2125/6413/2269 1708/5274/1852 +f 1866/6414/2010 1869/6415/2013 1867/6416/2011 +f 2126/6417/2270 1869/6418/2013 1866/6419/2010 +f 1864/5552/2008 2126/6420/2270 1866/6421/2010 +f 2068/6422/2212 1778/5399/1922 1776/5397/1920 +f 1780/6423/1924 1778/5399/1922 2068/6424/2212 +f 1782/6425/1926 1780/6426/1924 2068/6427/2212 +f 1999/6428/2143 1683/6429/1825 1681/6430/1827 +f 2107/6431/2251 1683/6432/1825 1999/6433/2143 +f 1997/6434/2141 2107/6435/2251 1999/6436/2143 +f 1758/5376/1902 1895/5691/2039 2020/6437/2164 +f 1934/5692/2079 1895/5691/2039 1758/5376/1902 +f 2127/6438/2271 1934/5692/2079 1758/5376/1902 +f 1936/6439/2080 1894/6440/2038 1895/5621/2039 +f 1893/6441/2037 1894/6442/2038 1936/6443/2080 +f 1892/6444/2036 1893/6445/2037 1936/6446/2080 +f 1891/6447/2035 1819/6448/1963 1817/6449/1961 +f 1821/5479/1965 1819/6450/1963 1891/6451/2035 +f 1823/5482/1967 1821/5479/1965 1891/6452/2035 +f 1892/6453/2036 1825/5484/1969 1823/5482/1967 +f 1870/6454/2015 1825/5484/1969 1892/6455/2036 +f 1936/6456/2080 1870/6457/2015 1892/6458/2036 +f 1925/5670/2069 2128/6459/2272 1927/5672/2071 +f 2085/6460/2229 2128/6461/2272 1925/5670/2069 +f 2083/6462/2227 2085/6463/2229 1925/5670/2069 +f 2013/6464/2157 2061/6465/2205 2011/6466/2155 +f 1724/6467/1868 2061/6468/2205 2013/6469/2157 +f 1726/6470/1870 1724/6471/1868 2013/6472/2157 +f 2062/6473/2206 1973/6474/2117 1971/6475/2113 +f 1992/5836/2136 1973/6476/2117 2062/6477/2206 +f 1720/6478/1864 1992/5836/2136 2062/6479/2206 +f 2129/6480/2273 1721/6481/1865 1723/6482/1867 +f 1719/6483/1863 1721/6484/1865 2129/6485/2273 +f 1988/6486/2133 1719/6487/1863 2129/6488/2273 +f 2129/6489/2273 1989/6490/2132 1988/6491/2133 +f 2126/6492/2270 1989/6493/2132 2129/6494/2273 +f 1723/6495/1867 2126/6496/2270 2129/6497/2273 +f 1929/6498/2073 1798/5434/1942 1800/5436/1944 +f 1670/5235/1814 1798/5434/1942 1929/6499/2073 +f 1668/5231/1812 1670/5235/1814 1929/6500/2073 +f 2094/6501/2238 1759/5377/1903 1761/5379/1905 +f 2069/6502/2213 1759/5377/1903 2094/6503/2238 +f 1657/5220/1801 2069/6504/2213 2094/6505/2238 +f 2124/6506/2268 1696/5261/1840 1698/5263/1842 +f 1694/5259/1838 1696/5261/1840 2124/6507/2268 +f 1692/5257/1836 1694/5259/1838 2124/6508/2268 +s 117 +f 2119/6509/2263 2030/5969/2174 2118/6510/2262 +f 2032/6511/2176 2030/5969/2174 2119/6512/2263 +f 2120/6513/2264 2032/6514/2176 2119/6515/2263 +s 102 +f 1850/5516/1994 1950/6516/2094 1848/5511/1992 +f 1852/6517/1996 1950/6518/2094 1850/5516/1994 +f 1944/5702/2088 1856/6519/2000 1858/5535/2002 +f 1946/5704/2090 1856/6520/2000 1944/5702/2088 +f 1946/5704/2090 2101/6521/2245 1856/6522/2000 +f 1948/6523/2092 2101/6524/2245 1946/5704/2090 +f 2132/6525/2274 2131/6526/2275 2130/6527/2276 +f 2133/6528/2277 2131/6526/2275 2132/6525/2274 +f 2053/6529/2197 2089/6530/2233 2051/6531/2196 +f 2054/6532/2198 2089/6533/2233 2053/6534/2197 +f 1914/6535/2058 1998/6536/2142 1913/6537/2057 +f 1915/5650/2059 1998/6538/2142 1914/6539/2058 +f 1915/5650/2059 1996/5861/2140 1998/6540/2142 +f 1916/6541/2060 1996/5861/2140 1915/5650/2059 +f 2099/6542/2243 1855/6543/1999 1853/5522/1997 +f 1857/6544/2001 1855/6545/1999 2099/6546/2243 +f 1674/5239/1818 2039/6547/2183 1672/5237/1816 +f 1676/5241/1820 2039/6548/2183 1674/5239/1818 +f 2038/6549/2182 1676/5241/1820 1678/5243/1822 +f 2039/6550/2183 1676/5241/1820 2038/6551/2182 +f 2060/6064/2204 1801/5437/1945 1799/5433/1941 +f 1917/6552/2061 1801/5437/1945 2060/6064/2204 +f 1982/6553/2126 1671/5236/1815 1669/5233/1813 +f 1980/6554/2124 1671/5236/1815 1982/6555/2126 +f 1922/5667/2066 1925/5670/2069 1923/5668/2067 +f 2083/6556/2227 1925/5670/2069 1922/5667/2066 +f 1803/6557/1947 1917/6558/2061 1805/6559/1949 +f 1801/5437/1945 1917/6560/2061 1803/6561/1947 +f 2134/6562/2278 1644/5207/1788 1646/5209/1790 +f 2135/6563/2279 1644/5207/1788 2134/6562/2278 +f 1648/5211/1792 2056/6057/2200 1699/6564/1843 +f 1650/5213/1794 2056/6057/2200 1648/5211/1792 +f 2136/6565/2280 1767/5385/1911 1769/5387/1913 +f 2133/6566/2277 1767/5385/1911 2136/6565/2280 +f 2133/6567/2277 1765/5383/1909 1767/5385/1911 +f 2132/6568/2274 1765/5383/1909 2133/6569/2277 +f 2065/6570/2209 2102/6571/2246 2066/6572/2210 +f 2064/6573/2208 2102/6574/2246 2065/6575/2209 +f 2125/6576/2269 1705/5270/1849 1703/5268/1847 +f 1707/5272/1851 1705/5270/1849 2125/6577/2269 +f 1731/6578/1877 1820/5476/1964 1822/5481/1966 +f 1732/6579/1876 1820/5476/1964 1731/6580/1877 +f 1771/6581/1916 1883/6582/2027 1748/5364/1892 +f 1813/6583/1957 1883/6584/2027 1771/6585/1916 +f 2043/6586/2187 1874/5577/2018 1876/5579/2020 +f 2045/6587/2189 1874/5577/2018 2043/6588/2187 +f 1813/6589/1957 1885/5591/2029 1883/6590/2027 +f 1814/6591/1958 1885/5591/2029 1813/6592/1957 +f 1814/6593/1958 1887/5594/2031 1885/5591/2029 +f 1815/5596/1959 1887/5594/2031 1814/6594/1958 +f 2076/6595/2218 2105/6596/2249 2084/6597/2228 +f 2074/6598/2220 2105/6599/2249 2076/6600/2218 +f 2088/6601/2232 1689/5254/1833 1687/5252/1831 +f 2054/6602/2198 1689/5254/1833 2088/6603/2232 +f 1787/6604/1931 1958/6605/2102 1796/6606/1940 +f 1786/6607/1930 1958/6608/2102 1787/6609/1931 +f 1748/5393/1892 1987/6610/2131 1772/5391/1915 +f 1750/6611/1894 1987/6612/2131 1748/5393/1892 +f 1869/6613/2013 1723/6614/1867 1725/6615/1869 +f 2126/6616/2270 1723/6617/1867 1869/6618/2013 +f 1713/6619/1857 1981/6620/2125 1711/6621/1855 +f 1715/6622/1859 1981/6623/2125 1713/6624/1857 +f 1884/5589/2028 1744/5356/1888 1746/5360/1890 +f 1886/5593/2030 1744/5356/1888 1884/5589/2028 +f 1684/5249/1828 1706/5271/1850 1682/5273/1826 +f 1686/5251/1830 1706/5271/1850 1684/5249/1828 +f 1938/5695/2082 1870/5574/2015 1936/5693/2080 +f 1871/5572/2014 1870/5574/2015 1938/5695/2082 +f 2086/6625/2230 1739/6626/1883 1737/5345/1881 +f 2022/6627/2166 1739/6628/1883 2086/6629/2230 +f 1695/5260/1839 2052/6630/2195 1697/5262/1841 +f 1693/5258/1837 2052/6631/2195 1695/5260/1839 +f 2137/6632/2281 1665/5228/1809 1663/5226/1807 +f 2109/6352/2254 1665/5228/1809 2137/6633/2281 +f 1860/6634/2004 1843/6635/1989 1990/6636/2134 +f 1845/6637/1987 1843/6638/1989 1860/6639/2004 +f 1731/6640/1877 1976/6641/2120 1733/5786/1875 +f 2138/6642/2282 1976/6643/2120 1731/6644/1877 +f 2139/6645/2283 1976/6646/2120 2138/6647/2282 +f 1972/6648/2116 1976/6649/2120 2139/6650/2283 +f 2140/6651/2284 1769/6652/1913 1770/6653/1914 +f 2136/6654/2280 1769/6655/1913 2140/6656/2284 +f 1881/5584/2025 2016/5936/2160 1882/6657/2026 +f 2018/5940/2162 2016/5936/2160 1881/5584/2025 +f 2142/6658/2285 1729/6659/1873 2141/6660/2286 +f 1727/6661/1871 1729/6662/1873 2142/6663/2285 +f 1990/6664/2134 1862/6665/2006 1860/6666/2004 +f 1989/6667/2132 1862/6668/2006 1990/6669/2134 +s 117 +f 2143/6670/2287 2030/5969/2174 2028/5967/2172 +f 2118/6671/2262 2030/5969/2174 2143/6670/2287 +s 102 +f 2100/6672/2244 1863/5549/2007 1865/6673/2009 +f 1861/6674/2005 1863/5549/2007 2100/6675/2244 +f 2123/6676/2267 1983/6677/2127 1985/6678/2129 +f 2092/6679/2236 1983/6680/2127 2123/6681/2267 +f 1660/5223/1804 1812/5460/1956 1658/5221/1802 +f 1662/5225/1806 1812/5460/1956 1660/5223/1804 +f 1653/5216/1797 1657/5220/1801 1655/5218/1799 +f 2069/6682/2213 1657/5220/1801 1653/5216/1797 +f 2144/6683/2288 1663/5226/1807 1661/5224/1805 +f 2137/6684/2281 1663/5226/1807 2144/6685/2288 +f 1650/5213/1794 2055/6055/2199 2056/6057/2200 +f 1652/5215/1796 2055/6055/2199 1650/5213/1794 +f 1877/5580/2021 2075/6686/2219 1879/5582/2023 +f 2074/6687/2220 2075/6688/2219 1877/5580/2021 +f 1760/5378/1904 2020/6689/2164 1762/5380/1906 +f 1758/5376/1902 2020/6690/2164 1760/5378/1904 +f 2145/6691/2289 1765/5383/1909 2132/6692/2274 +f 1763/5381/1907 1765/5383/1909 2145/6693/2289 +f 2067/6694/2211 1731/6695/1877 1822/6696/1966 +f 2138/6697/2282 1731/6698/1877 2067/6699/2211 +f 1989/6700/2132 1864/5552/2008 1862/6701/2006 +f 2126/6702/2270 1864/5552/2008 1989/6703/2132 +s 113 +f 2146/6704/2290 2098/6705/2242 1959/6706/2105 +f 2097/6707/2241 2098/6708/2242 2146/6709/2290 +s 102 +f 1880/6710/2024 2033/5973/2177 2044/6711/2188 +f 1882/5586/2026 2033/5973/2177 1880/6712/2024 +f 2021/6713/2165 1762/6714/1906 2020/6715/2164 +f 2022/6716/2166 1762/6717/1906 2021/6718/2165 +s 113 +f 2147/6719/2291 2104/6720/2248 2009/6721/2153 +f 2103/6722/2247 2104/6723/2248 2147/6724/2291 +s 102 +f 2131/6526/2275 2133/6528/2277 2136/6654/2280 +f 1980/6725/2124 1673/5238/1817 1671/5236/1815 +f 1652/5215/1796 1654/5217/1798 2055/6055/2199 +f 1811/5458/1955 1654/5217/1798 1656/5219/1800 +f 1756/5374/1900 1754/5372/1898 2057/6726/2201 +f 1756/5374/1900 2127/6438/2271 1758/5376/1902 +f 1956/6727/2100 1983/6728/2127 2092/6729/2236 +f 1732/6730/1876 1818/6731/1962 1820/5476/1964 +f 2017/6732/2161 2019/5942/2163 2079/6733/2223 +f 2061/6734/2205 1724/6735/1868 1722/6736/1866 +f 1992/5836/2136 1975/6737/2119 1973/6738/2117 +f 1974/6739/2118 1976/6740/2120 1972/6741/2116 +f 2150/6742/2292 2149/6743/2293 2148/6744/2294 +f 2151/6745/2295 2149/6743/2293 2150/6742/2292 +f 2152/6746/2296 2151/6747/2295 2150/6742/2292 +f 2153/6748/2297 2151/6749/2295 2152/6746/2296 +f 2154/6750/2298 1659/5222/1803 2093/6751/2237 +f 2155/6752/2299 1659/5222/1803 2154/6750/2298 +f 2156/6753/2300 2155/6752/2299 2154/6750/2298 +f 2153/6748/2297 2155/6752/2299 2156/6753/2300 +f 2157/6754/2301 2149/6755/2293 2151/6756/2295 +f 2148/6757/2294 2149/6755/2293 2157/6754/2301 +f 2140/6758/2284 2148/6759/2294 2157/6754/2301 +f 2158/6760/2302 2148/6761/2294 2140/6758/2284 +f 2154/6750/2298 2145/6762/2289 2132/6763/2274 +f 1763/5381/1907 2145/6764/2289 2154/6750/2298 +f 2093/6765/2237 1763/5381/1907 2154/6750/2298 +f 2159/6766/2303 1712/6767/1856 2111/6354/2255 +f 1714/6768/1858 1712/6769/1856 2159/6770/2303 +f 2160/6771/2304 1714/6772/1858 2159/6773/2303 +f 2130/6774/2276 2156/6775/2300 2154/6776/2298 +f 2153/6777/2297 2156/6775/2300 2130/6778/2276 +f 2151/6756/2295 2153/6777/2297 2130/6779/2276 +f 2158/6760/2302 2161/6780/2305 2148/6781/2294 +f 2162/6782/2306 2161/6783/2305 2158/6760/2302 +f 2160/6784/2304 2162/6785/2306 2158/6760/2302 +f 2157/6786/2301 2136/6654/2280 2140/6787/2284 +f 2131/6526/2275 2136/6654/2280 2157/6786/2301 +f 2163/6788/2307 2148/6744/2294 2161/6789/2305 +f 2150/6742/2292 2148/6744/2294 2163/6790/2307 +f 2158/6791/2302 1770/6792/1914 2160/6793/2304 +f 2140/6794/2284 1770/6795/1914 2158/6796/2302 +f 2070/6131/2214 2160/6797/2304 1770/5389/1914 +f 2071/6798/2215 2160/6799/2304 2070/6131/2214 +f 2080/6187/2224 2160/6800/2304 2071/6801/2215 +f 1714/6802/1858 2160/6803/2304 2080/6187/2224 +f 2155/6752/2299 1661/5224/1805 1659/5222/1803 +f 2144/6804/2288 1661/5224/1805 2155/6752/2299 +f 2131/6805/2275 2151/6756/2295 2130/6806/2276 +f 2157/6754/2301 2151/6756/2295 2131/6807/2275 +f 2159/6808/2303 2162/6809/2306 2160/6810/2304 +f 2161/6811/2305 2162/6812/2306 2159/6813/2303 +f 2130/6527/2276 2154/6814/2298 2132/6525/2274 +f 2164/6815/2308 2111/6354/2255 2110/6351/2253 +f 2159/6816/2303 2111/6354/2255 2164/6815/2308 +f 2165/6817/2309 2159/6818/2303 2164/6815/2308 +f 2161/6819/2305 2159/6820/2303 2165/6817/2309 +f 2163/6821/2307 2161/6822/2305 2165/6817/2309 +f 2166/6823/2310 2137/6824/2281 2144/6825/2288 +f 2167/6826/2311 2137/6827/2281 2166/6828/2310 +f 2168/6829/2312 2167/6826/2311 2166/6830/2310 +f 2152/6746/2296 2167/6826/2311 2168/6831/2312 +f 2153/6748/2297 2152/6746/2296 2168/6832/2312 +f 2163/6833/2307 2169/6834/2313 2150/6742/2292 +f 2170/6835/2314 2169/6834/2313 2163/6836/2307 +f 2165/6817/2309 2170/6837/2314 2163/6838/2307 +f 2164/6815/2308 2170/6839/2314 2165/6817/2309 +f 2169/6834/2313 2109/6352/2254 2137/6840/2281 +f 2110/6351/2253 2109/6352/2254 2169/6834/2313 +f 2170/6841/2314 2110/6351/2253 2169/6834/2313 +f 2164/6815/2308 2110/6351/2253 2170/6842/2314 +f 2155/6752/2299 2166/6843/2310 2144/6844/2288 +f 2168/6845/2312 2166/6846/2310 2155/6752/2299 +f 2153/6748/2297 2168/6847/2312 2155/6752/2299 +f 2169/6834/2313 2152/6746/2296 2150/6742/2292 +f 2167/6826/2311 2152/6746/2296 2169/6834/2313 +f 2137/6848/2281 2167/6826/2311 2169/6834/2313 +s 124 +f 2173/6849/2315 2172/6850/2316 2171/6851/2317 +f 2174/6852/2318 2172/6850/2316 2173/6849/2315 +f 2175/6853/2319 2174/6852/2318 2173/6849/2315 +f 2176/6854/2320 2174/6852/2318 2175/6853/2319 +f 2177/6855/2321 2176/6854/2320 2175/6853/2319 +f 2178/6856/2322 2176/6854/2320 2177/6855/2321 +f 2179/6857/2323 2178/6856/2322 2177/6855/2321 +f 2177/6855/2321 2180/6858/2324 2179/6857/2323 +f 2181/6859/2325 2180/6858/2324 2177/6855/2321 +f 2175/6853/2319 2181/6859/2325 2177/6855/2321 +f 2182/6860/2326 2181/6859/2325 2175/6853/2319 +f 2183/6861/2327 2182/6860/2326 2175/6853/2319 +f 2184/6862/2328 2182/6860/2326 2183/6861/2327 +f 2185/6863/2329 2184/6862/2328 2183/6861/2327 +f 2188/6864/2330 2187/6865/2331 2186/6866/2332 +f 2175/6853/2319 2187/6867/2331 2188/6868/2330 +f 2189/6869/2333 2175/6853/2319 2188/6870/2330 +f 2183/6861/2327 2175/6853/2319 2189/6871/2333 +f 2190/6872/2334 2183/6861/2327 2189/6873/2333 +f 2185/6863/2329 2183/6861/2327 2190/6874/2334 +f 2187/6875/2331 2191/6876/2335 2186/6877/2332 +f 2192/6878/2336 2191/6879/2335 2187/6880/2331 +f 2193/6881/2337 2192/6878/2336 2187/6882/2331 +f 2194/6883/2338 2192/6878/2336 2193/6881/2337 +f 2195/6884/2339 2194/6883/2338 2193/6881/2337 +f 2189/6885/2333 2196/6886/2340 2190/6887/2334 +f 2197/6888/2341 2196/6886/2340 2189/6889/2333 +f 2188/6890/2330 2197/6888/2341 2189/6891/2333 +f 2198/6892/2342 2197/6888/2341 2188/6893/2330 +f 2186/6894/2332 2198/6892/2342 2188/6895/2330 +f 2175/6853/2319 2193/6881/2337 2187/6896/2331 +f 2199/6897/2343 2193/6881/2337 2175/6853/2319 +f 2173/6849/2315 2199/6897/2343 2175/6853/2319 +f 2200/6898/2344 2199/6897/2343 2173/6849/2315 +f 2171/6851/2317 2200/6898/2344 2173/6849/2315 +f 2181/6859/2325 2201/6899/2345 2180/6858/2324 +f 2202/6900/2346 2201/6899/2345 2181/6859/2325 +f 2182/6860/2326 2202/6900/2346 2181/6859/2325 +f 2203/6901/2347 2202/6900/2346 2182/6860/2326 +f 2184/6862/2328 2203/6901/2347 2182/6860/2326 +f 2204/6902/2348 2176/6854/2320 2178/6856/2322 +f 2205/6903/2349 2176/6854/2320 2204/6904/2348 +f 2205/6905/2349 2174/6852/2318 2176/6854/2320 +f 2206/6906/2350 2174/6852/2318 2205/6907/2349 +f 2207/6908/2351 2199/6897/2343 2200/6898/2344 +f 2195/6884/2339 2199/6897/2343 2207/6909/2351 +f 2199/6897/2343 2195/6884/2339 2193/6881/2337 +f 2172/6850/2316 2174/6852/2318 2206/6910/2350 +s 126 +f 2210/6911/2352 2209/6912/2353 2208/6913/2354 +f 2211/6914/2355 2209/6912/2353 2210/6911/2352 +f 2212/6915/2356 2211/6914/2355 2210/6911/2352 +f 2213/6916/2357 2211/6914/2355 2212/6915/2356 +f 2214/6917/2358 2213/6916/2357 2212/6915/2356 +f 2215/6918/2359 2213/6916/2357 2214/6917/2358 +f 2218/6919/2360 2217/6920/2361 2216/6921/2362 +f 2219/6922/2363 2217/6920/2361 2218/6919/2360 +f 2209/6912/2353 2219/6922/2363 2218/6919/2360 +f 2220/6923/2364 2219/6922/2363 2209/6912/2353 +f 2221/6924/2365 2220/6923/2364 2209/6912/2353 +f 2223/6925/2366 2216/6921/2362 2222/6926/2367 +f 2218/6919/2360 2216/6921/2362 2223/6925/2366 +f 2226/6927/2368 2225/6928/2369 2224/6929/2370 +f 2227/6930/2371 2225/6928/2369 2226/6927/2368 +f 2211/6914/2355 2221/6924/2365 2209/6912/2353 +f 2213/6916/2357 2221/6924/2365 2211/6914/2355 +f 2220/6923/2364 2229/6931/2372 2228/6932/2373 +f 2230/6933/2374 2229/6931/2372 2220/6923/2364 +f 2221/6924/2365 2230/6933/2374 2220/6923/2364 +f 2231/6934/2375 2230/6933/2374 2221/6924/2365 +f 2232/6935/2376 2231/6934/2375 2221/6924/2365 +f 2233/6936/2377 2231/6934/2375 2232/6935/2376 +f 2234/6937/2378 2233/6936/2377 2232/6935/2376 +f 2235/6938/2379 2233/6936/2377 2234/6937/2378 +f 2236/6939/2380 2235/6938/2379 2234/6937/2378 +f 2224/6940/2370 2235/6938/2379 2236/6939/2380 +f 2237/6941/2381 2224/6940/2370 2236/6939/2380 +f 2226/6942/2368 2224/6940/2370 2237/6941/2381 +f 2238/6943/2382 2226/6942/2368 2237/6941/2381 +f 2239/6944/2383 2226/6942/2368 2238/6943/2382 +f 2240/6945/2384 2239/6944/2383 2238/6943/2382 +f 2241/6946/2385 2239/6944/2383 2240/6945/2384 +f 2242/6947/2386 2241/6946/2385 2240/6945/2384 +f 2243/6948/2387 2241/6946/2385 2242/6947/2386 +f 2244/6949/2388 2243/6948/2387 2242/6947/2386 +f 2245/6950/2389 2243/6948/2387 2244/6949/2388 +f 2248/6951/2390 2247/6952/2391 2246/6953/2392 +f 2249/6954/2393 2247/6952/2391 2248/6951/2390 +f 2227/6930/2371 2249/6954/2393 2248/6951/2390 +f 2250/6955/2394 2249/6954/2393 2227/6930/2371 +f 2251/6956/2395 2250/6955/2394 2227/6930/2371 +f 2252/6957/2396 2250/6955/2394 2251/6956/2395 +f 2253/6958/2397 2252/6957/2396 2251/6956/2395 +f 2216/6921/2362 2254/6959/2398 2222/6926/2367 +f 2255/6960/2399 2254/6959/2398 2216/6921/2362 +f 2217/6920/2361 2255/6960/2399 2216/6921/2362 +f 2228/6932/2373 2255/6960/2399 2217/6920/2361 +f 2219/6922/2363 2228/6932/2373 2217/6920/2361 +f 2220/6923/2364 2228/6932/2373 2219/6922/2363 +f 2222/6961/2367 2257/6962/2400 2256/6963/2401 +f 2258/6964/2402 2257/6962/2400 2222/6961/2367 +f 2254/6965/2398 2258/6964/2402 2222/6961/2367 +f 2259/6966/2403 2258/6964/2402 2254/6965/2398 +f 2260/6967/2404 2259/6966/2403 2254/6965/2398 +f 2213/6916/2357 2232/6935/2376 2221/6924/2365 +f 2234/6937/2378 2232/6935/2376 2213/6916/2357 +f 2215/6918/2359 2234/6937/2378 2213/6916/2357 +f 2236/6939/2380 2234/6937/2378 2215/6918/2359 +f 2261/6968/2405 2236/6939/2380 2215/6918/2359 +f 2264/6969/2406 2263/6970/2407 2262/6971/2408 +f 2265/6972/2409 2263/6973/2407 2264/6974/2406 +f 2266/6975/2410 2265/6976/2409 2264/6977/2406 +f 2267/6978/2411 2265/6979/2409 2266/6980/2410 +f 2270/6981/2412 2269/6982/2413 2268/6983/2414 +f 2249/6954/2393 2269/6984/2413 2270/6985/2412 +f 2271/6986/2415 2249/6954/2393 2270/6987/2412 +f 2247/6952/2391 2249/6954/2393 2271/6986/2415 +f 2238/6943/2382 2261/6968/2405 2240/6945/2384 +f 2236/6939/2380 2261/6968/2405 2238/6943/2382 +f 2237/6941/2381 2236/6939/2380 2238/6943/2382 +f 2257/6988/2400 2273/6989/2416 2272/6990/2417 +f 2258/6991/2402 2273/6989/2416 2257/6988/2400 +f 2258/6991/2402 2274/6992/2418 2273/6989/2416 +f 2259/6993/2403 2274/6992/2418 2258/6991/2402 +f 2276/6994/2419 2260/6995/2404 2275/6996/2420 +f 2274/6992/2418 2260/6995/2404 2276/6994/2419 +f 2255/6997/2399 2260/6967/2404 2254/6965/2398 +f 2275/6998/2420 2260/6967/2404 2255/6997/2399 +f 2272/6990/2417 2245/6999/2389 2257/7000/2400 +f 2277/7001/2421 2245/6999/2389 2272/6990/2417 +f 2278/7002/2422 2249/6954/2393 2250/6955/2394 +f 2269/7003/2413 2249/6954/2393 2278/7004/2422 +f 2245/7005/2389 2256/6963/2401 2257/7006/2400 +f 2244/7007/2388 2256/6963/2401 2245/7005/2389 +f 2239/6944/2383 2251/7008/2395 2226/6942/2368 +f 2241/6946/2385 2251/7008/2395 2239/6944/2383 +f 2241/6946/2385 2253/7009/2397 2251/7008/2395 +f 2243/6948/2387 2253/7009/2397 2241/6946/2385 +f 2263/7010/2407 2265/7011/2409 2279/7012/2423 +f 2224/6929/2370 2280/7013/2424 2235/7014/2379 +f 2227/6930/2371 2226/6927/2368 2251/6956/2395 +f 2260/6995/2404 2274/6992/2418 2259/6993/2403 +f 2245/6950/2389 2253/7009/2397 2243/6948/2387 +f 2283/7015/2425 2282/7016/2426 2281/7017/2427 +f 2244/6949/2388 2282/7016/2426 2283/7015/2425 +f 2284/7018/2428 2244/6949/2388 2283/7015/2425 +f 2256/7019/2401 2244/6949/2388 2284/7018/2428 +f 2256/7020/2401 2223/6925/2366 2222/6926/2367 +f 2285/7021/2429 2223/6925/2366 2256/7020/2401 +f 2284/7022/2428 2285/7021/2429 2256/7020/2401 +f 2286/7023/2430 2285/7021/2429 2284/7022/2428 +f 2288/7024/2431 2240/6945/2384 2287/7025/2432 +f 2242/6947/2386 2240/6945/2384 2288/7024/2431 +f 2282/7016/2426 2242/6947/2386 2288/7024/2431 +f 2244/6949/2388 2242/6947/2386 2282/7016/2426 +f 2287/7025/2432 2215/6918/2359 2214/6917/2358 +f 2261/6968/2405 2215/6918/2359 2287/7025/2432 +f 2240/6945/2384 2261/6968/2405 2287/7025/2432 +f 2290/7026/2433 2286/7023/2430 2289/7027/2434 +f 2285/7021/2429 2286/7023/2430 2290/7026/2433 +f 2223/6925/2366 2285/7021/2429 2290/7026/2433 +f 2290/7026/2433 2218/6919/2360 2223/6925/2366 +f 2208/6913/2354 2218/6919/2360 2290/7026/2433 +f 2208/6913/2354 2209/6912/2353 2218/6919/2360 +f 2281/7017/2427 2292/7028/2435 2291/7029/2436 +f 2293/7030/2437 2292/7028/2435 2281/7017/2427 +f 2282/7016/2426 2293/7030/2437 2281/7017/2427 +f 2288/7024/2431 2293/7030/2437 2282/7016/2426 +f 2293/7030/2437 2294/7031/2438 2292/7028/2435 +f 2295/7032/2439 2294/7031/2438 2293/7030/2437 +f 2288/7024/2431 2295/7032/2439 2293/7030/2437 +f 2287/7025/2432 2295/7032/2439 2288/7024/2431 +f 2295/7032/2439 2296/7033/2440 2294/7031/2438 +f 2297/7034/2441 2296/7033/2440 2295/7032/2439 +f 2287/7025/2432 2297/7034/2441 2295/7032/2439 +f 2214/6917/2358 2297/7034/2441 2287/7025/2432 +f 2297/7034/2441 2298/7035/2442 2296/7033/2440 +f 2299/7036/2443 2298/7035/2442 2297/7034/2441 +f 2214/6917/2358 2299/7036/2443 2297/7034/2441 +f 2212/6915/2356 2299/7036/2443 2214/6917/2358 +f 2299/7036/2443 2300/7037/2444 2298/7035/2442 +f 2301/7038/2445 2300/7037/2444 2299/7036/2443 +f 2212/6915/2356 2301/7038/2445 2299/7036/2443 +f 2210/6911/2352 2301/7038/2445 2212/6915/2356 +f 2301/7038/2445 2302/7039/2446 2300/7037/2444 +f 2303/7040/2447 2302/7039/2446 2301/7038/2445 +f 2210/6911/2352 2303/7040/2447 2301/7038/2445 +f 2208/6913/2354 2303/7040/2447 2210/6911/2352 +f 2303/7040/2447 2304/7041/2448 2302/7039/2446 +f 2289/7027/2434 2304/7041/2448 2303/7040/2447 +f 2208/6913/2354 2289/7027/2434 2303/7040/2447 +f 2290/7026/2433 2289/7027/2434 2208/6913/2354 +f 2284/7018/2428 2306/7042/2449 2305/7043/2450 +f 2283/7015/2425 2306/7042/2449 2284/7018/2428 +f 2283/7015/2425 2291/7029/2436 2306/7042/2449 +f 2281/7017/2427 2291/7029/2436 2283/7015/2425 +f 2289/7027/2434 2307/7044/2451 2304/7041/2448 +f 2286/7023/2430 2307/7044/2451 2289/7027/2434 +f 2305/7045/2450 2286/7023/2430 2284/7022/2428 +f 2307/7044/2451 2286/7023/2430 2305/7045/2450 +f 2310/7046/2452 2309/7047/2453 2308/7048/2454 +f 2311/7049/2455 2309/7047/2453 2310/7046/2452 +f 2312/7050/2456 2311/7049/2455 2310/7046/2452 +f 2313/7051/2457 2311/7049/2455 2312/7050/2456 +f 2314/7052/2458 2313/7051/2457 2312/7050/2456 +f 2315/7053/2459 2313/7051/2457 2314/7052/2458 +f 2316/7054/2460 2315/7053/2459 2314/7052/2458 +f 2317/7055/2461 2315/7053/2459 2316/7054/2460 +f 2318/7056/2462 2317/7055/2461 2316/7054/2460 +f 2319/7057/2463 2317/7055/2461 2318/7056/2462 +f 2302/7039/2446 2319/7057/2463 2318/7056/2462 +f 2304/7041/2448 2319/7057/2463 2302/7039/2446 +f 2318/7056/2462 2300/7037/2444 2302/7039/2446 +f 2320/7058/2464 2300/7037/2444 2318/7056/2462 +f 2316/7054/2460 2320/7058/2464 2318/7056/2462 +f 2321/7059/2465 2320/7058/2464 2316/7054/2460 +f 2314/7052/2458 2321/7059/2465 2316/7054/2460 +f 2322/7060/2466 2321/7059/2465 2314/7052/2458 +f 2312/7050/2456 2322/7060/2466 2314/7052/2458 +f 2323/7061/2467 2322/7060/2466 2312/7050/2456 +f 2310/7046/2452 2323/7061/2467 2312/7050/2456 +f 2326/7062/2468 2325/7063/2469 2324/7064/2470 +f 2327/7065/2471 2325/7063/2469 2326/7062/2468 +f 2328/7066/2472 2327/7065/2471 2326/7062/2468 +f 2329/7067/2473 2327/7065/2471 2328/7066/2472 +f 2330/7068/2474 2329/7067/2473 2328/7066/2472 +f 2331/7069/2475 2329/7067/2473 2330/7068/2474 +f 2305/7043/2450 2331/7069/2475 2330/7068/2474 +f 2306/7042/2449 2331/7069/2475 2305/7043/2450 +f 2327/7065/2471 2332/7070/2476 2325/7063/2469 +f 2333/7071/2477 2332/7070/2476 2327/7065/2471 +f 2329/7067/2473 2333/7071/2477 2327/7065/2471 +f 2334/7072/2478 2333/7071/2477 2329/7067/2473 +f 2331/7069/2475 2334/7072/2478 2329/7067/2473 +f 2335/7073/2479 2334/7072/2478 2331/7069/2475 +f 2306/7042/2449 2335/7073/2479 2331/7069/2475 +f 2291/7029/2436 2335/7073/2479 2306/7042/2449 +f 2333/7071/2477 2308/7048/2454 2332/7070/2476 +f 2310/7046/2452 2308/7048/2454 2333/7071/2477 +f 2334/7072/2478 2310/7046/2452 2333/7071/2477 +f 2323/7061/2467 2310/7046/2452 2334/7072/2478 +f 2335/7073/2479 2323/7061/2467 2334/7072/2478 +f 2336/7074/2480 2323/7061/2467 2335/7073/2479 +f 2291/7029/2436 2336/7074/2480 2335/7073/2479 +f 2292/7028/2435 2336/7074/2480 2291/7029/2436 +f 2317/7055/2461 2337/7075/2481 2315/7053/2459 +f 2338/7076/2482 2337/7075/2481 2317/7055/2461 +f 2319/7057/2463 2338/7076/2482 2317/7055/2461 +f 2339/7077/2483 2338/7076/2482 2319/7057/2463 +f 2304/7041/2448 2339/7077/2483 2319/7057/2463 +f 2307/7044/2451 2339/7077/2483 2304/7041/2448 +f 2338/7076/2482 2340/7078/2484 2337/7075/2481 +f 2341/7079/2485 2340/7078/2484 2338/7076/2482 +f 2339/7077/2483 2341/7079/2485 2338/7076/2482 +f 2342/7080/2486 2341/7079/2485 2339/7077/2483 +f 2307/7044/2451 2342/7080/2486 2339/7077/2483 +f 2305/7045/2450 2342/7080/2486 2307/7044/2451 +f 2343/7081/2487 2296/7033/2440 2298/7035/2442 +f 2344/7082/2488 2296/7033/2440 2343/7081/2487 +f 2322/7060/2466 2344/7082/2488 2343/7081/2487 +f 2336/7074/2480 2344/7082/2488 2322/7060/2466 +f 2323/7061/2467 2336/7074/2480 2322/7060/2466 +f 2320/7058/2464 2298/7035/2442 2300/7037/2444 +f 2343/7081/2487 2298/7035/2442 2320/7058/2464 +f 2321/7059/2465 2343/7081/2487 2320/7058/2464 +f 2322/7060/2466 2343/7081/2487 2321/7059/2465 +f 2330/7083/2474 2342/7080/2486 2305/7045/2450 +f 2345/7084/2489 2342/7080/2486 2330/7083/2474 +f 2328/7085/2472 2345/7084/2489 2330/7083/2474 +f 2326/7086/2468 2345/7084/2489 2328/7085/2472 +f 2345/7084/2489 2341/7079/2485 2342/7080/2486 +f 2346/7087/2490 2341/7079/2485 2345/7084/2489 +f 2347/7088/2491 2346/7087/2490 2345/7084/2489 +f 2324/7089/2470 2345/7084/2489 2326/7086/2468 +f 2347/7088/2491 2345/7084/2489 2324/7089/2470 +f 2292/7028/2435 2344/7082/2488 2336/7074/2480 +f 2294/7031/2438 2344/7082/2488 2292/7028/2435 +f 2346/7087/2490 2340/7078/2484 2341/7079/2485 +f 2344/7082/2488 2294/7031/2438 2296/7033/2440 +f 2350/7090/2492 2349/7091/2493 2348/7092/2494 +f 2351/7093/2495 2349/7091/2493 2350/7090/2492 +f 2352/7094/2496 2351/7093/2495 2350/7090/2492 +f 2353/7095/2497 2351/7093/2495 2352/7096/2496 +f 2354/7097/2498 2353/7095/2497 2352/7098/2496 +f 2355/7099/2499 2353/7095/2497 2354/7097/2498 +f 2356/7100/2500 2355/7099/2499 2354/7097/2498 +f 2359/7101/2501 2358/7102/2502 2357/7103/2503 +f 2360/7104/2504 2358/7102/2502 2359/7101/2501 +f 2361/7105/2505 2360/7104/2504 2359/7101/2501 +f 2362/7106/2506 2360/7104/2504 2361/7105/2505 +f 2363/7107/2507 2362/7106/2506 2361/7105/2505 +f 2364/7108/2508 2362/7106/2506 2363/7107/2507 +f 2367/7109/2509 2366/7110/2510 2365/7111/2511 +f 2368/7112/2512 2366/7113/2510 2367/7114/2509 +f 2369/7115/2513 2368/7116/2512 2367/7117/2509 +f 2362/7106/2506 2368/7118/2512 2369/7115/2513 +f 2360/7104/2504 2362/7106/2506 2369/7115/2513 +f 2349/7091/2493 2370/7119/2514 2348/7092/2494 +f 2371/7120/2515 2370/7119/2514 2349/7091/2493 +f 2353/7095/2497 2371/7121/2515 2349/7091/2493 +f 2355/7099/2499 2371/7122/2515 2353/7095/2497 +f 2354/7097/2498 2372/7123/2516 2356/7100/2500 +f 2373/7124/2517 2372/7123/2516 2354/7097/2498 +f 2374/7125/2518 2373/7124/2517 2354/7097/2498 +f 2377/7126/2519 2376/7127/2520 2375/7128/2521 +f 2378/7129/2522 2376/7127/2520 2377/7126/2519 +f 2381/7130/2523 2380/7131/2524 2379/7132/2525 +f 2382/7133/2526 2380/7134/2524 2381/7135/2523 +f 2368/7136/2512 2364/7137/2508 2366/7138/2510 +f 2362/7106/2506 2364/7139/2508 2368/7140/2512 +f 2383/7141/2527 2352/7142/2496 2350/7090/2492 +f 2374/7143/2518 2352/7144/2496 2383/7145/2527 +f 2384/7146/2528 2371/7147/2515 2355/7099/2499 +f 2385/7148/2529 2371/7149/2515 2384/7150/2528 +f 2386/7151/2530 2371/7152/2515 2385/7153/2529 +f 2370/7119/2514 2371/7154/2515 2386/7155/2530 +f 2369/7115/2513 2358/7102/2502 2360/7104/2504 +f 2349/7091/2493 2351/7093/2495 2353/7095/2497 +f 2352/7156/2496 2374/7157/2518 2354/7097/2498 +f 2389/7158/2531 2388/7159/2532 2387/7160/2533 +f 2390/7161/2534 2388/7159/2532 2389/7158/2531 +f 2391/7162/2535 2390/7161/2534 2389/7158/2531 +f 2392/7163/2536 2390/7161/2534 2391/7162/2535 +f 2393/7164/2537 2392/7163/2536 2391/7162/2535 +f 2394/7165/2538 2392/7163/2536 2393/7164/2537 +f 2395/7166/2539 2394/7165/2538 2393/7164/2537 +f 2396/7167/2540 2394/7165/2538 2395/7166/2539 +f 2397/7168/2541 2396/7167/2540 2395/7166/2539 +f 2392/7163/2536 2399/7169/2542 2398/7170/2543 +f 2400/7171/2544 2399/7169/2542 2392/7163/2536 +f 2394/7165/2538 2400/7171/2544 2392/7163/2536 +f 2401/7172/2545 2400/7171/2544 2394/7165/2538 +f 2402/7173/2546 2401/7172/2545 2394/7165/2538 +f 2403/7174/2547 2401/7172/2545 2402/7173/2546 +f 2404/7175/2548 2403/7174/2547 2402/7173/2546 +f 2407/7176/2549 2406/7177/2550 2405/7178/2551 +f 2408/7179/2552 2406/7177/2550 2407/7176/2549 +f 2409/7180/2553 2408/7179/2552 2407/7176/2549 +f 2410/7181/2554 2408/7179/2552 2409/7180/2553 +f 2411/7182/2555 2410/7181/2554 2409/7180/2553 +f 2412/7183/2556 2410/7181/2554 2411/7182/2555 +f 2408/7179/2552 2387/7160/2533 2406/7177/2550 +f 2389/7158/2531 2387/7160/2533 2408/7179/2552 +f 2410/7181/2554 2389/7158/2531 2408/7179/2552 +f 2391/7162/2535 2389/7158/2531 2410/7181/2554 +f 2412/7183/2556 2391/7162/2535 2410/7181/2554 +f 2413/7184/2557 2391/7162/2535 2412/7183/2556 +f 2416/7185/2558 2415/7186/2559 2414/7187/2560 +f 2417/7188/2561 2415/7186/2559 2416/7185/2558 +f 2418/7189/2562 2417/7190/2561 2416/7185/2558 +f 2419/7191/2563 2417/7192/2561 2418/7189/2562 +f 2420/7193/2564 2419/7194/2563 2418/7189/2562 +f 2421/7195/2565 2419/7196/2563 2420/7193/2564 +f 2417/7197/2561 2422/7198/2566 2415/7186/2559 +f 2423/7199/2567 2422/7200/2566 2417/7201/2561 +f 2424/7202/2568 2423/7203/2567 2417/7204/2561 +f 2425/7205/2569 2423/7206/2567 2424/7207/2568 +f 2426/7208/2570 2425/7209/2569 2424/7210/2568 +f 2427/7211/2571 2425/7212/2569 2426/7213/2570 +f 2423/7214/2567 2428/7215/2572 2422/7216/2566 +f 2429/7217/2573 2428/7218/2572 2423/7219/2567 +f 2425/7220/2569 2429/7221/2573 2423/7222/2567 +f 2430/7223/2574 2429/7224/2573 2425/7225/2569 +f 2427/7226/2571 2430/7227/2574 2425/7228/2569 +f 2431/7229/2575 2430/7230/2574 2427/7231/2571 +f 2429/7232/2573 2432/7233/2576 2428/7234/2572 +f 2433/7235/2577 2432/7236/2576 2429/7237/2573 +f 2434/7238/2578 2433/7239/2577 2429/7240/2573 +f 2435/7241/2579 2433/7242/2577 2434/7243/2578 +f 2436/7244/2580 2435/7245/2579 2434/7246/2578 +f 2404/7247/2548 2435/7248/2579 2436/7249/2580 +f 2439/7250/2581 2438/7251/2582 2437/7252/2583 +f 2440/7253/2584 2438/7251/2582 2439/7254/2581 +f 2407/7176/2549 2440/7255/2584 2439/7256/2581 +f 2441/7257/2585 2440/7258/2584 2407/7176/2549 +f 2405/7178/2551 2441/7259/2585 2407/7176/2549 +f 2433/7260/2577 2442/7261/2586 2432/7262/2576 +f 2443/7263/2587 2442/7261/2586 2433/7264/2577 +f 2435/7265/2579 2443/7266/2587 2433/7267/2577 +f 2444/7268/2588 2443/7269/2587 2435/7270/2579 +f 2424/7271/2568 2445/7272/2589 2426/7273/2570 +f 2419/7274/2563 2445/7275/2589 2424/7276/2568 +f 2417/7277/2561 2419/7278/2563 2424/7279/2568 +f 2434/7280/2578 2446/7281/2590 2436/7282/2580 +f 2431/7283/2575 2446/7284/2590 2434/7285/2578 +f 2430/7286/2574 2431/7287/2575 2434/7288/2578 +f 2448/7289/2591 2418/7189/2562 2447/7290/2592 +f 2420/7193/2564 2418/7189/2562 2448/7291/2591 +f 2390/7161/2534 2398/7170/2543 2388/7159/2532 +f 2392/7163/2536 2398/7170/2543 2390/7161/2534 +f 2439/7292/2581 2409/7180/2553 2407/7176/2549 +f 2449/7293/2593 2409/7180/2553 2439/7294/2581 +f 2413/7184/2557 2393/7164/2537 2391/7162/2535 +f 2450/7295/2594 2393/7164/2537 2413/7184/2557 +f 2409/7180/2553 2451/7296/2595 2411/7182/2555 +f 2449/7297/2593 2451/7298/2595 2409/7180/2553 +f 2450/7299/2594 2395/7166/2539 2393/7164/2537 +f 2452/7300/2596 2395/7166/2539 2450/7301/2594 +f 2453/7302/2597 2419/7303/2563 2421/7195/2565 +f 2445/7304/2589 2419/7305/2563 2453/7306/2597 +f 2402/7173/2546 2435/7307/2579 2404/7308/2548 +f 2444/7309/2588 2435/7310/2579 2402/7173/2546 +f 2454/7311/2598 2443/7312/2587 2444/7313/2588 +f 2455/7314/2599 2443/7315/2587 2454/7316/2598 +f 2396/7167/2540 2402/7173/2546 2394/7165/2538 +f 2429/7317/2573 2430/7318/2574 2434/7319/2578 +f 2455/7320/2599 2442/7261/2586 2443/7321/2587 +f 2397/7168/2541 2395/7166/2539 2452/7300/2596 +f 2456/7322/2600 2451/7323/2595 2449/7324/2593 +f 2459/7325/2601 2458/7326/2602 2457/7327/2603 +f 2437/7252/2583 2458/7326/2602 2459/7325/2601 +f 2460/7328/2604 2437/7252/2583 2459/7325/2601 +f 2439/7329/2581 2437/7252/2583 2460/7328/2604 +f 2449/7330/2593 2439/7331/2581 2460/7328/2604 +f 2462/7332/2605 2414/7187/2560 2461/7333/2606 +f 2416/7185/2558 2414/7187/2560 2462/7332/2605 +f 2463/7334/2607 2416/7185/2558 2462/7332/2605 +f 2418/7189/2562 2416/7185/2558 2463/7335/2607 +f 2447/7336/2592 2418/7189/2562 2463/7337/2607 +f 2464/7338/2608 2397/7339/2541 2452/7340/2596 +f 2465/7341/2609 2397/7339/2541 2464/7338/2608 +f 2466/7342/2610 2465/7341/2609 2464/7338/2608 +f 2467/7343/2611 2465/7341/2609 2466/7342/2610 +f 2468/7344/2612 2460/7328/2604 2459/7325/2601 +f 2469/7345/2613 2460/7328/2604 2468/7344/2612 +f 2470/7346/2614 2469/7347/2613 2468/7344/2612 +f 2456/7348/2600 2469/7349/2613 2470/7350/2614 +f 2463/7351/2607 2471/7352/2615 2447/7353/2592 +f 2472/7354/2616 2471/7355/2615 2463/7356/2607 +f 2462/7332/2605 2472/7357/2616 2463/7358/2607 +f 2461/7333/2606 2472/7359/2616 2462/7332/2605 +f 2475/7360/2617 2474/7361/2618 2473/7362/2619 +f 2359/7101/2501 2474/7361/2618 2475/7360/2617 +f 2361/7105/2505 2359/7101/2501 2475/7360/2617 +f 2402/7173/2546 2361/7105/2505 2444/7363/2588 +f 2363/7107/2507 2361/7105/2505 2402/7173/2546 +f 2364/7364/2508 2363/7107/2507 2402/7173/2546 +f 2465/7365/2609 2364/7366/2508 2397/7168/2541 +f 2366/7367/2510 2364/7368/2508 2465/7369/2609 +f 2476/7370/2620 2366/7371/2510 2465/7372/2609 +f 2454/7373/2598 2477/7374/2621 2455/7375/2599 +f 2475/7376/2617 2477/7377/2621 2454/7378/2598 +f 2478/7379/2622 2475/7380/2617 2473/7381/2619 +f 2477/7382/2621 2475/7383/2617 2478/7384/2622 +f 2454/7385/2598 2361/7105/2505 2475/7360/2617 +f 2444/7386/2588 2361/7105/2505 2454/7387/2598 +f 2396/7167/2540 2364/7388/2508 2402/7173/2546 +f 2397/7168/2541 2364/7389/2508 2396/7167/2540 +f 2480/7390/2623 2471/7391/2615 2479/7392/2624 +f 2447/7393/2592 2471/7394/2615 2480/7395/2623 +f 2449/7396/2593 2469/7397/2613 2456/7398/2600 +f 2460/7328/2604 2469/7399/2613 2449/7400/2593 +f 2465/7401/2609 2467/7402/2611 2476/7403/2620 +f 2483/7404/2625 2482/7405/2626 2481/7406/2627 +f 2484/7407/2628 2482/7408/2626 2483/7409/2625 +f 2485/7410/2629 2484/7411/2628 2483/7412/2625 +f 2486/7413/2630 2484/7414/2628 2485/7415/2629 +f 2487/7416/2631 2486/7417/2630 2485/7418/2629 +f 2489/7419/2632 2278/7420/2422 2488/7421/2633 +f 2490/7422/2634 2278/7423/2422 2489/7424/2632 +f 2263/7425/2407 2490/7426/2634 2489/7427/2632 +f 2279/7012/2423 2490/7428/2634 2263/7429/2407 +f 2484/7430/2628 2492/7431/2635 2491/7432/2636 +f 2493/7433/2637 2492/7434/2635 2484/7435/2628 +f 2486/7436/2630 2493/7437/2637 2484/7438/2628 +f 2494/7439/2638 2493/7440/2637 2486/7441/2630 +f 2496/7442/2639 2482/7443/2626 2495/7444/2640 +f 2481/7445/2627 2482/7446/2626 2496/7447/2639 +f 2276/7448/2419 2481/7449/2627 2496/7450/2639 +f 2497/7451/2641 2481/7452/2627 2276/7453/2419 +f 2497/7454/2641 2483/7455/2625 2481/7456/2627 +f 2485/7457/2629 2483/7458/2625 2497/7459/2641 +f 2498/7460/2642 2485/7461/2629 2497/7462/2641 +f 2487/7463/2631 2485/7464/2629 2498/7465/2642 +f 2488/7466/2633 2252/6957/2396 2253/6958/2397 +f 2250/6955/2394 2252/6957/2396 2488/7467/2633 +f 2278/7468/2422 2250/6955/2394 2488/7469/2633 +f 2490/7470/2634 2269/7471/2413 2278/7472/2422 +f 2268/7473/2414 2269/7474/2413 2490/7475/2634 +f 2279/7012/2423 2268/7476/2414 2490/7477/2634 +f 2248/6951/2390 2225/6928/2369 2227/6930/2371 +f 2246/6953/2392 2225/6928/2369 2248/6951/2390 +f 2225/6928/2369 2280/7478/2424 2224/6929/2370 +f 2246/6953/2392 2280/7479/2424 2225/6928/2369 +f 2493/7480/2637 2499/7481/2643 2492/7482/2635 +f 2494/7483/2638 2499/7484/2643 2493/7485/2637 +f 2501/7486/2644 2494/7487/2638 2500/7488/2645 +f 2499/7489/2643 2494/7490/2638 2501/7491/2644 +f 2273/7492/2416 2496/7493/2639 2495/7494/2640 +f 2274/7495/2418 2496/7496/2639 2273/7497/2416 +f 2253/7009/2397 2502/7498/2646 2488/7499/2633 +f 2262/7500/2408 2263/7501/2407 2489/7502/2632 +f 2274/7503/2418 2276/7504/2419 2496/7505/2639 +f 2503/7506/2647 2486/7507/2630 2487/7508/2631 +f 2504/7509/2648 2486/7510/2630 2503/7511/2647 +f 2267/7512/2411 2504/7513/2648 2503/7514/2647 +f 2266/7515/2410 2504/7516/2648 2267/7517/2411 +f 2264/7518/2406 2505/7519/2649 2500/7520/2645 +f 2506/7521/2650 2505/7522/2649 2264/7523/2406 +f 2262/7524/2408 2506/7525/2650 2264/7526/2406 +f 2489/7527/2632 2506/7528/2650 2262/7529/2408 +f 2506/7530/2650 2507/7531/2651 2505/7532/2649 +f 2508/7533/2652 2507/7534/2651 2506/7535/2650 +f 2489/7536/2632 2508/7537/2652 2506/7538/2650 +f 2488/7539/2633 2508/7540/2652 2489/7541/2632 +f 2502/7542/2646 2508/7543/2652 2488/7544/2633 +f 2507/7545/2651 2508/7546/2652 2502/7547/2646 +f 2509/7548/2653 2507/7549/2651 2502/7550/2646 +f 2510/7551/2654 2502/7552/2646 2253/7009/2397 +f 2509/7553/2653 2502/7554/2646 2510/7555/2654 +f 2277/7556/2421 2509/7557/2653 2510/7558/2654 +f 2504/7559/2648 2494/7560/2638 2486/7561/2630 +f 2266/7562/2410 2494/7563/2638 2504/7564/2648 +f 2266/7565/2410 2500/7566/2645 2494/7567/2638 +f 2264/7568/2406 2500/7569/2645 2266/7570/2410 +f 2510/7571/2654 2245/6950/2389 2277/7572/2421 +f 2253/7009/2397 2245/6950/2389 2510/7573/2654 +f 2513/7574/2655 2512/7575/2656 2511/7576/2657 +f 2514/7577/2658 2512/7575/2656 2513/7574/2655 +f 2515/7578/2659 2514/7577/2658 2513/7574/2655 +f 2516/7579/2660 2514/7577/2658 2515/7578/2659 +f 2517/7580/2661 2516/7579/2660 2515/7578/2659 +f 2518/7581/2662 2516/7579/2660 2517/7580/2661 +f 2519/7582/2663 2518/7581/2662 2517/7580/2661 +f 2522/7583/2664 2521/7584/2665 2520/7585/2666 +f 2523/7586/2667 2521/7584/2665 2522/7583/2664 +f 2524/7587/2668 2523/7586/2667 2522/7583/2664 +f 2525/7588/2669 2523/7586/2667 2524/7587/2668 +f 2526/7589/2670 2525/7588/2669 2524/7587/2668 +f 2527/7590/2671 2525/7588/2669 2526/7589/2670 +f 2529/7591/2672 2516/7579/2660 2528/7592/2673 +f 2514/7577/2658 2516/7579/2660 2529/7591/2672 +f 2530/7593/2674 2514/7577/2658 2529/7591/2672 +f 2512/7575/2656 2514/7577/2658 2530/7593/2674 +f 2531/7594/2675 2512/7575/2656 2530/7593/2674 +f 2511/7576/2657 2512/7575/2656 2531/7594/2675 +f 2521/7595/2665 2532/7596/2676 2520/7597/2666 +f 2533/7598/2677 2532/7596/2676 2521/7595/2665 +f 2534/7599/2678 2533/7598/2677 2521/7595/2665 +f 2535/7600/2679 2533/7598/2677 2534/7599/2678 +f 2533/7598/2677 2536/7601/2680 2532/7596/2676 +f 2531/7594/2675 2536/7601/2680 2533/7598/2677 +f 2535/7600/2679 2531/7594/2675 2533/7598/2677 +f 2511/7576/2657 2531/7594/2675 2535/7600/2679 +f 2539/7602/2681 2538/7603/2682 2537/7604/2683 +f 2540/7605/2684 2538/7606/2682 2539/7607/2681 +f 2541/7608/2685 2540/7609/2684 2539/7610/2681 +f 2542/7611/2686 2540/7612/2684 2541/7613/2685 +f 2543/7614/2687 2527/7590/2671 2542/7615/2686 +f 2525/7588/2669 2527/7590/2671 2543/7614/2687 +f 2544/7616/2688 2525/7588/2669 2543/7614/2687 +f 2540/7617/2684 2526/7618/2670 2538/7619/2682 +f 2527/7620/2671 2526/7621/2670 2540/7622/2684 +f 2542/7623/2686 2527/7624/2671 2540/7625/2684 +f 2547/7626/2689 2546/7627/2690 2545/7628/2691 +f 2539/7629/2681 2546/7630/2690 2547/7631/2689 +f 2541/7632/2685 2539/7633/2681 2547/7634/2689 +f 2521/7584/2665 2549/7635/2692 2548/7636/2693 +f 2523/7586/2667 2549/7635/2692 2521/7584/2665 +f 2523/7586/2667 2544/7616/2688 2549/7635/2692 +f 2525/7588/2669 2544/7616/2688 2523/7586/2667 +f 2521/7595/2665 2548/7637/2693 2534/7599/2678 +f 2530/7593/2674 2536/7601/2680 2531/7594/2675 +f 2519/7582/2663 2280/7638/2424 2246/6953/2392 +f 2235/7639/2379 2280/7640/2424 2519/7582/2663 +f 2517/7580/2661 2235/7641/2379 2519/7582/2663 +f 2233/7642/2377 2235/7643/2379 2517/7580/2661 +f 2515/7578/2659 2233/7642/2377 2517/7580/2661 +f 2231/7644/2375 2233/7642/2377 2515/7578/2659 +f 2513/7574/2655 2231/7644/2375 2515/7578/2659 +f 2230/7645/2374 2231/7644/2375 2513/7574/2655 +f 2511/7576/2657 2230/7645/2374 2513/7574/2655 +f 2229/7646/2372 2230/7645/2374 2511/7576/2657 +f 2535/7600/2679 2229/7646/2372 2511/7576/2657 +f 2228/7647/2373 2229/7646/2372 2535/7600/2679 +f 2534/7599/2678 2228/7647/2373 2535/7600/2679 +f 2255/6997/2399 2228/7647/2373 2534/7599/2678 +f 2550/7648/2694 2545/7649/2691 2546/7650/2690 +f 2551/7651/2695 2545/7652/2691 2550/7648/2694 +f 2552/7653/2696 2551/7651/2695 2550/7648/2694 +f 2553/7654/2697 2551/7651/2695 2552/7653/2696 +f 2554/7655/2698 2553/7654/2697 2552/7653/2696 +f 2271/6986/2415 2553/7654/2697 2554/7655/2698 +f 2555/7656/2699 2271/6986/2415 2554/7655/2698 +f 2247/6952/2391 2271/6986/2415 2555/7657/2699 +f 2246/6953/2392 2247/6952/2391 2555/7658/2699 +f 2541/7659/2685 2503/7660/2647 2542/7661/2686 +f 2267/7662/2411 2503/7663/2647 2541/7664/2685 +f 2547/7665/2689 2267/7666/2411 2541/7667/2685 +f 2265/7011/2409 2267/7668/2411 2547/7669/2689 +f 2545/7670/2691 2265/7011/2409 2547/7671/2689 +f 2279/7012/2423 2265/7011/2409 2545/7672/2691 +f 2268/7673/2414 2279/7012/2423 2545/7674/2691 +f 2544/7616/2688 2497/7675/2641 2549/7635/2692 +f 2498/7676/2642 2497/7675/2641 2544/7616/2688 +f 2543/7614/2687 2498/7676/2642 2544/7616/2688 +f 2487/7677/2631 2498/7676/2642 2543/7614/2687 +f 2542/7615/2686 2487/7677/2631 2543/7614/2687 +f 2503/7678/2647 2487/7677/2631 2542/7615/2686 +f 2519/7582/2663 2556/7679/2700 2518/7581/2662 +f 2557/7680/2701 2556/7681/2700 2519/7582/2663 +f 2246/6953/2392 2557/7682/2701 2519/7582/2663 +f 2555/7683/2699 2557/7684/2701 2246/6953/2392 +f 2549/7635/2692 2275/6996/2420 2548/7636/2693 +f 2276/6994/2419 2275/6996/2420 2549/7635/2692 +f 2497/7675/2641 2276/6994/2419 2549/7635/2692 +f 2275/6998/2420 2534/7599/2678 2548/7637/2693 +f 2255/6997/2399 2534/7599/2678 2275/6998/2420 +f 2551/7651/2695 2268/7685/2414 2545/7686/2691 +f 2553/7654/2697 2268/7687/2414 2551/7651/2695 +f 2553/7654/2697 2270/7688/2412 2268/7689/2414 +f 2271/6986/2415 2270/7690/2412 2553/7654/2697 +f 2557/7691/2701 2558/7692/2702 2556/7693/2700 +f 2555/7694/2699 2558/7695/2702 2557/7696/2701 +f 2559/7697/2703 2554/7655/2698 2552/7653/2696 +f 2558/7698/2702 2554/7655/2698 2559/7697/2703 +f 2558/7699/2702 2555/7700/2699 2554/7655/2698 +f 2495/7701/2640 2272/7702/2417 2273/7703/2416 +f 2560/7704/2704 2272/7705/2417 2495/7706/2640 +f 2561/7707/2705 2560/7708/2704 2495/7709/2640 +f 2564/7710/2706 2563/7711/2707 2562/7712/2708 +f 2277/7713/2421 2563/7714/2707 2564/7715/2706 +f 2509/7716/2653 2277/7717/2421 2564/7718/2706 +f 2482/7719/2626 2561/7720/2705 2495/7721/2640 +f 2491/7722/2636 2561/7723/2705 2482/7724/2626 +f 2484/7725/2628 2491/7726/2636 2482/7727/2626 +f 2565/7728/2709 2509/7729/2653 2564/7730/2706 +f 2507/7731/2651 2509/7732/2653 2565/7733/2709 +f 2566/7734/2710 2277/7735/2421 2272/7736/2417 +f 2563/7737/2707 2277/7738/2421 2566/7739/2710 +f 2566/7740/2710 2272/7741/2417 2560/7742/2704 +f 2568/7743/2711 2501/7744/2644 2567/7745/2712 +f 2499/7746/2643 2501/7747/2644 2568/7748/2711 +f 2569/7749/2713 2499/7750/2643 2568/7751/2711 +f 2492/7752/2635 2499/7753/2643 2569/7754/2713 +f 2570/7755/2714 2492/7756/2635 2569/7757/2713 +f 2491/7758/2636 2492/7759/2635 2570/7760/2714 +f 2571/7761/2715 2491/7762/2636 2570/7763/2714 +f 2573/7764/2716 2570/7765/2714 2572/7766/2717 +f 2571/7767/2715 2570/7768/2714 2573/7769/2716 +f 2574/7770/2718 2571/7771/2715 2573/7772/2716 +f 2575/7773/2719 2571/7774/2715 2574/7775/2718 +f 2576/7776/2720 2575/7777/2719 2574/7778/2718 +f 2566/7779/2710 2575/7780/2719 2576/7781/2720 +f 2577/7782/2721 2507/7783/2651 2565/7784/2709 +f 2505/7785/2649 2507/7786/2651 2577/7787/2721 +f 2500/7788/2645 2505/7789/2649 2577/7790/2721 +f 2577/7791/2721 2501/7792/2644 2500/7793/2645 +f 2567/7794/2712 2501/7795/2644 2577/7796/2721 +f 2578/7797/2722 2567/7798/2712 2577/7799/2721 +f 2560/7800/2704 2575/7801/2719 2566/7802/2710 +f 2561/7803/2705 2575/7804/2719 2560/7805/2704 +f 2561/7806/2705 2571/7807/2715 2575/7808/2719 +f 2491/7809/2636 2571/7810/2715 2561/7811/2705 +f 2580/7812/2723 2579/7813/2724 2578/7814/2722 +f 2581/7815/2725 2579/7816/2724 2580/7817/2723 +f 2562/7818/2708 2581/7819/2725 2580/7820/2723 +f 2582/7821/2726 2581/7822/2725 2562/7823/2708 +f 2563/7824/2707 2582/7825/2726 2562/7826/2708 +f 2583/7827/2727 2582/7828/2726 2563/7829/2707 +f 2566/7830/2710 2583/7831/2727 2563/7832/2707 +f 2576/7833/2720 2583/7834/2727 2566/7835/2710 +f 2565/7836/2709 2578/7837/2722 2577/7838/2721 +f 2580/7839/2723 2578/7840/2722 2565/7841/2709 +f 2564/7842/2706 2580/7843/2723 2565/7844/2709 +f 2562/7845/2708 2580/7846/2723 2564/7847/2706 +f 2583/7848/2727 2584/7849/2728 2582/7850/2726 +f 2585/7851/2729 2584/7852/2728 2583/7853/2727 +f 2576/7854/2720 2585/7855/2729 2583/7856/2727 +f 2586/7857/2730 2585/7858/2729 2576/7859/2720 +f 2589/7860/2731 2588/7861/2732 2587/7862/2733 +f 2579/7863/2724 2588/7864/2732 2589/7865/2731 +f 2588/7866/2732 2581/7867/2725 2590/7868/2734 +f 2579/7869/2724 2581/7870/2725 2588/7871/2732 +f 2593/7872/2735 2592/7873/2736 2591/7874/2737 +f 2594/7875/2738 2592/7876/2736 2593/7877/2735 +f 2595/7878/2739 2594/7879/2738 2593/7880/2735 +f 2596/7881/2740 2594/7882/2738 2595/7883/2739 +f 2597/7884/2741 2596/7885/2740 2595/7886/2739 +f 2598/7887/2742 2596/7888/2740 2597/7889/2741 +f 2599/7890/2743 2598/7891/2742 2597/7892/2741 +f 2600/7893/2744 2598/7894/2742 2599/7895/2743 +f 2601/7896/2745 2600/7897/2744 2599/7898/2743 +f 2602/7899/2746 2600/7900/2744 2601/7901/2745 +f 2594/7902/2738 2586/7903/2730 2592/7904/2736 +f 2585/7905/2729 2586/7906/2730 2594/7907/2738 +f 2596/7908/2740 2585/7909/2729 2594/7910/2738 +f 2584/7911/2728 2585/7912/2729 2596/7913/2740 +f 2598/7914/2742 2584/7915/2728 2596/7916/2740 +f 2590/7917/2734 2584/7918/2728 2598/7919/2742 +f 2600/7920/2744 2590/7921/2734 2598/7922/2742 +f 2588/7923/2732 2590/7924/2734 2600/7925/2744 +f 2587/7926/2733 2588/7927/2732 2600/7928/2744 +f 2569/7929/2713 2572/7930/2717 2570/7931/2714 +f 2603/7932/2747 2572/7933/2717 2569/7934/2713 +f 2568/7935/2711 2603/7936/2747 2569/7937/2713 +f 2604/7938/2748 2603/7939/2747 2568/7940/2711 +f 2567/7941/2712 2604/7942/2748 2568/7943/2711 +f 2589/7944/2731 2604/7945/2748 2567/7946/2712 +f 2578/7947/2722 2589/7948/2731 2567/7949/2712 +f 2579/7950/2724 2589/7951/2731 2578/7952/2722 +f 2606/7953/2749 2591/7954/2737 2605/7955/2750 +f 2593/7956/2735 2591/7957/2737 2606/7958/2749 +f 2607/7959/2751 2593/7960/2735 2606/7961/2749 +f 2595/7962/2739 2593/7963/2735 2607/7964/2751 +f 2608/7965/2752 2595/7966/2739 2607/7967/2751 +f 2597/7968/2741 2595/7969/2739 2608/7970/2752 +f 2609/7971/2753 2597/7972/2741 2608/7973/2752 +f 2610/7974/2754 2597/7975/2741 2609/7976/2753 +f 2587/7977/2733 2604/7978/2748 2589/7979/2731 +f 2611/7980/2755 2604/7981/2748 2587/7982/2733 +f 2602/7983/2746 2611/7984/2755 2587/7985/2733 +f 2612/7986/2756 2611/7987/2755 2602/7988/2746 +f 2601/7989/2745 2612/7990/2756 2602/7991/2746 +f 2613/7992/2757 2612/7993/2756 2601/7994/2745 +f 2614/7995/2758 2613/7996/2757 2601/7997/2745 +f 2611/7998/2755 2603/7999/2747 2604/8000/2748 +f 2615/8001/2759 2603/8002/2747 2611/8003/2755 +f 2612/8004/2756 2615/8005/2759 2611/8006/2755 +f 2616/8007/2760 2615/8008/2759 2612/8009/2756 +f 2613/8010/2757 2616/8011/2760 2612/8012/2756 +f 2617/8013/2761 2616/8014/2760 2613/8015/2757 +f 2615/8016/2759 2572/8017/2717 2603/8018/2747 +f 2618/8019/2762 2572/8020/2717 2615/8021/2759 +f 2616/8022/2760 2618/8023/2762 2615/8024/2759 +f 2619/8025/2763 2618/8026/2762 2616/8027/2760 +f 2617/8028/2761 2619/8029/2763 2616/8030/2760 +f 2620/8031/2764 2619/8032/2763 2617/8033/2761 +f 2618/8034/2762 2573/8035/2716 2572/8036/2717 +f 2621/8037/2765 2573/8038/2716 2618/8039/2762 +f 2619/8040/2763 2621/8041/2765 2618/8042/2762 +f 2622/8043/2766 2621/8044/2765 2619/8045/2763 +f 2620/8046/2764 2622/8047/2766 2619/8048/2763 +f 2623/8049/2767 2622/8050/2766 2620/8051/2764 +f 2621/8052/2765 2574/8053/2718 2573/8054/2716 +f 2624/8055/2768 2574/8056/2718 2621/8057/2765 +f 2622/8058/2766 2624/8059/2768 2621/8060/2765 +f 2625/8061/2769 2624/8062/2768 2622/8063/2766 +f 2623/8064/2767 2625/8065/2769 2622/8066/2766 +f 2626/8067/2770 2625/8068/2769 2623/8069/2767 +f 2624/8070/2768 2576/8071/2720 2574/8072/2718 +f 2586/8073/2730 2576/8074/2720 2624/8075/2768 +f 2625/8076/2769 2586/8077/2730 2624/8078/2768 +f 2592/8079/2736 2586/8080/2730 2625/8081/2769 +f 2591/8082/2737 2592/8083/2736 2625/8084/2769 +f 2625/8085/2769 2605/8086/2750 2591/8087/2737 +f 2626/8088/2770 2605/8089/2750 2625/8090/2769 +f 2610/8091/2754 2599/8092/2743 2597/8093/2741 +f 2614/8094/2758 2599/8095/2743 2610/8096/2754 +f 2590/8097/2734 2582/8098/2726 2584/8099/2728 +f 2581/8100/2725 2582/8101/2726 2590/8102/2734 +f 2601/8103/2745 2599/8104/2743 2614/8105/2758 +f 2602/8106/2746 2587/8107/2733 2600/8108/2744 +f 2629/8109/2771 2628/8110/2772 2627/8111/2773 +f 2630/8112/2774 2628/8110/2772 2629/8109/2771 +f 2631/8113/2775 2630/8112/2774 2629/8109/2771 +f 2632/8114/2776 2630/8112/2774 2631/8113/2775 +f 2633/8115/2777 2632/8114/2776 2631/8113/2775 +f 2634/8116/2778 2632/8114/2776 2633/8115/2777 +f 2635/8117/2779 2634/8116/2778 2633/8115/2777 +f 2636/8118/2780 2634/8116/2778 2635/8117/2779 +f 2637/8119/2781 2636/8118/2780 2635/8117/2779 +f 2638/8120/2782 2636/8118/2780 2637/8119/2781 +f 2639/8121/2783 2638/8120/2782 2637/8119/2781 +f 2640/8122/2784 2638/8120/2782 2639/8121/2783 +f 2641/8123/2785 2640/8122/2784 2639/8121/2783 +f 2642/8124/2786 2640/8122/2784 2641/8123/2785 +f 2643/8125/2787 2642/8124/2786 2641/8123/2785 +f 2309/7047/2453 2642/8124/2786 2643/8125/2787 +f 2644/8126/2788 2309/7047/2453 2643/8125/2787 +f 2308/7048/2454 2309/7047/2453 2644/8126/2788 +f 2645/8127/2789 2308/7048/2454 2644/8126/2788 +f 2332/7070/2476 2308/7048/2454 2645/8127/2789 +f 2325/7063/2469 2332/7070/2476 2645/8127/2789 +f 2630/8112/2774 2324/7089/2470 2628/8110/2772 +f 2347/7088/2491 2324/7089/2470 2630/8112/2774 +f 2632/8114/2776 2347/7088/2491 2630/8112/2774 +f 2346/7087/2490 2347/7088/2491 2632/8114/2776 +f 2634/8116/2778 2346/7087/2490 2632/8114/2776 +f 2340/7078/2484 2346/7087/2490 2634/8116/2778 +f 2636/8118/2780 2340/7078/2484 2634/8116/2778 +f 2337/7075/2481 2340/7078/2484 2636/8118/2780 +f 2638/8120/2782 2337/7075/2481 2636/8118/2780 +f 2315/7053/2459 2337/7075/2481 2638/8120/2782 +f 2640/8122/2784 2315/7053/2459 2638/8120/2782 +f 2313/7051/2457 2315/7053/2459 2640/8122/2784 +f 2642/8124/2786 2313/7051/2457 2640/8122/2784 +f 2311/7049/2455 2313/7051/2457 2642/8124/2786 +f 2309/7047/2453 2311/7049/2455 2642/8124/2786 +f 2609/8128/2753 2646/8129/2790 2610/8130/2754 +f 2647/8131/2791 2646/8132/2790 2609/8133/2753 +f 2648/8134/2792 2647/8135/2791 2609/8136/2753 +f 2649/8137/2793 2647/8138/2791 2648/8139/2792 +f 2650/8140/2794 2649/8137/2793 2648/8141/2792 +f 2650/8140/2794 2652/8142/2795 2651/8143/2796 +f 2653/8144/2797 2652/8142/2795 2650/8140/2794 +f 2648/8145/2792 2653/8146/2797 2650/8140/2794 +f 2608/8147/2752 2653/8148/2797 2648/8149/2792 +f 2609/8150/2753 2608/8151/2752 2648/8152/2792 +f 2656/8153/2798 2655/8154/2799 2654/8155/2800 +f 2657/8156/2801 2655/8157/2799 2656/8158/2798 +f 2605/8159/2750 2657/8160/2801 2656/8161/2798 +f 2626/8162/2770 2657/8163/2801 2605/8164/2750 +f 2657/8165/2801 2658/8166/2802 2655/8167/2799 +f 2659/8168/2803 2658/8169/2802 2657/8170/2801 +f 2626/8171/2770 2659/8172/2803 2657/8173/2801 +f 2623/8174/2767 2659/8175/2803 2626/8176/2770 +f 2659/8177/2803 2660/8178/2804 2658/8179/2802 +f 2661/8180/2805 2660/8181/2804 2659/8182/2803 +f 2623/8183/2767 2661/8184/2805 2659/8185/2803 +f 2620/8186/2764 2661/8187/2805 2623/8188/2767 +f 2661/8189/2805 2662/8190/2806 2660/8191/2804 +f 2663/8192/2807 2662/8193/2806 2661/8194/2805 +f 2620/8195/2764 2663/8196/2807 2661/8197/2805 +f 2617/8198/2761 2663/8199/2807 2620/8200/2764 +f 2663/8201/2807 2664/8202/2808 2662/8203/2806 +f 2665/8204/2809 2664/8205/2808 2663/8206/2807 +f 2617/8207/2761 2665/8208/2809 2663/8209/2807 +f 2613/8210/2757 2665/8211/2809 2617/8212/2761 +f 2665/8213/2809 2666/8214/2810 2664/8215/2808 +f 2667/8216/2811 2666/8217/2810 2665/8218/2809 +f 2613/8219/2757 2667/8220/2811 2665/8221/2809 +f 2614/8222/2758 2667/8223/2811 2613/8224/2757 +f 2667/8225/2811 2668/8226/2812 2666/8227/2810 +f 2646/8228/2790 2668/8229/2812 2667/8230/2811 +f 2614/8231/2758 2646/8232/2790 2667/8233/2811 +f 2610/8234/2754 2646/8235/2790 2614/8236/2758 +f 2656/8237/2798 2606/8238/2749 2605/8239/2750 +f 2652/8142/2795 2606/8240/2749 2656/8237/2798 +f 2654/8241/2800 2652/8142/2795 2656/8237/2798 +f 2651/8143/2796 2652/8142/2795 2654/8241/2800 +f 2669/8242/2813 2645/8127/2789 2644/8126/2788 +f 2670/8243/2814 2645/8127/2789 2669/8244/2813 +f 2671/8245/2815 2670/8246/2814 2669/8247/2813 +f 2627/8248/2773 2670/8249/2814 2671/8250/2815 +f 2628/8251/2772 2670/8252/2814 2627/8253/2773 +f 2325/7063/2469 2670/8254/2814 2628/8255/2772 +f 2324/7064/2470 2325/7063/2469 2628/8256/2772 +f 2672/8257/2816 2654/8258/2800 2655/8259/2799 +f 2651/8260/2796 2654/8258/2800 2672/8257/2816 +f 2650/8261/2794 2651/8260/2796 2672/8257/2816 +f 2672/8257/2816 2649/8262/2793 2650/8261/2794 +f 2673/8263/2817 2649/8262/2793 2672/8257/2816 +f 2668/8264/2812 2673/8265/2817 2672/8257/2816 +f 2675/8266/2818 2674/8267/2819 2641/8268/2785 +f 2676/8269/2820 2674/8270/2819 2675/8271/2818 +f 2669/8272/2813 2676/8273/2820 2675/8274/2818 +f 2673/8275/2817 2647/8276/2791 2649/8137/2793 +f 2668/8277/2812 2647/8278/2791 2673/8275/2817 +f 2607/8279/2751 2653/8280/2797 2608/8281/2752 +f 2606/8282/2749 2653/8283/2797 2607/8284/2751 +f 2674/8285/2819 2643/8125/2787 2641/8123/2785 +f 2676/8286/2820 2643/8125/2787 2674/8287/2819 +f 2676/8288/2820 2644/8126/2788 2643/8125/2787 +f 2669/8289/2813 2644/8126/2788 2676/8290/2820 +f 2658/8291/2802 2672/8257/2816 2655/8259/2799 +f 2660/8292/2804 2672/8257/2816 2658/8291/2802 +f 2662/8293/2806 2672/8257/2816 2660/8292/2804 +f 2664/8294/2808 2672/8257/2816 2662/8295/2806 +f 2672/8257/2816 2666/8296/2810 2668/8297/2812 +f 2664/8298/2808 2666/8296/2810 2672/8257/2816 +f 2639/8299/2783 2675/8300/2818 2641/8301/2785 +f 2637/8302/2781 2675/8303/2818 2639/8304/2783 +f 2635/8305/2779 2675/8306/2818 2637/8307/2781 +f 2633/8308/2777 2675/8309/2818 2635/8310/2779 +f 2631/8311/2775 2675/8312/2818 2633/8313/2777 +f 2629/8314/2771 2675/8315/2818 2631/8316/2775 +f 2627/8317/2773 2675/8318/2818 2629/8319/2771 +f 2671/8320/2815 2675/8321/2818 2627/8322/2773 +f 2652/8142/2795 2653/8323/2797 2606/8324/2749 +f 2646/8325/2790 2647/8326/2791 2668/8327/2812 +f 2670/8328/2814 2325/7063/2469 2645/8127/2789 +f 2669/8329/2813 2675/8330/2818 2671/8331/2815 +f 2677/8332/2821 2350/7090/2492 2348/7092/2494 +f 2383/8333/2527 2350/7090/2492 2677/8332/2821 +f 2678/8334/2822 2383/8335/2527 2677/8332/2821 +f 2382/8336/2526 2383/8337/2527 2678/8334/2822 +f 2679/8338/2823 2382/8339/2526 2678/8334/2822 +f 2380/8340/2524 2382/8341/2526 2679/8338/2823 +f 2680/8342/2824 2380/8343/2524 2679/8338/2823 +f 2681/8344/2825 2380/8345/2524 2680/8342/2824 +f 2682/8346/2826 2681/8344/2825 2680/8342/2824 +f 2683/8347/2827 2681/8344/2825 2682/8346/2826 +f 2684/8348/2828 2683/8347/2827 2682/8346/2826 +f 2685/8349/2829 2683/8347/2827 2684/8348/2828 +f 2378/7129/2522 2686/8350/2830 2376/7127/2520 +f 2348/7092/2494 2686/8350/2830 2378/7129/2522 +f 2687/8351/2831 2348/7092/2494 2378/7129/2522 +f 2677/8332/2821 2348/7092/2494 2687/8352/2831 +f 2520/7597/2666 2677/8332/2821 2687/8353/2831 +f 2678/8334/2822 2677/8332/2821 2520/7597/2666 +f 2532/7596/2676 2678/8334/2822 2520/7597/2666 +f 2679/8338/2823 2678/8334/2822 2532/7596/2676 +f 2536/7601/2680 2679/8338/2823 2532/7596/2676 +f 2680/8342/2824 2679/8338/2823 2536/7601/2680 +f 2530/7593/2674 2680/8342/2824 2536/7601/2680 +f 2529/7591/2672 2680/8342/2824 2530/7593/2674 +f 2688/8354/2832 2370/8355/2514 2386/8356/2530 +f 2686/8357/2830 2370/8355/2514 2688/8354/2832 +f 2689/8358/2833 2686/8357/2830 2688/8354/2832 +f 2376/8359/2520 2686/8357/2830 2689/8358/2833 +f 2690/8360/2834 2376/8359/2520 2689/8358/2833 +f 2375/8361/2521 2376/8359/2520 2690/8360/2834 +f 2691/8362/2835 2375/8361/2521 2690/8360/2834 +f 2692/8363/2836 2375/8361/2521 2691/8362/2835 +f 2472/8364/2616 2692/8363/2836 2691/8362/2835 +f 2461/7333/2606 2692/8363/2836 2472/8365/2616 +f 2537/8366/2683 2694/8367/2837 2693/8368/2838 +f 2695/8369/2839 2694/8367/2837 2537/8370/2683 +f 2696/8371/2840 2695/8369/2839 2537/8372/2683 +f 2697/8373/2841 2695/8369/2839 2696/8374/2840 +f 2698/8375/2842 2697/8376/2841 2696/8377/2840 +f 2699/8378/2843 2697/8379/2841 2698/8380/2842 +f 2700/8381/2844 2699/8382/2843 2698/8383/2842 +f 2701/8384/2845 2524/8385/2668 2522/8386/2664 +f 2702/8387/2846 2524/8388/2668 2701/8389/2845 +f 2377/7126/2519 2702/8390/2846 2701/8391/2845 +f 2703/8392/2847 2702/8393/2846 2377/7126/2519 +f 2704/8394/2848 2703/8395/2847 2377/7126/2519 +f 2698/8396/2842 2703/8397/2847 2704/8394/2848 +f 2700/8381/2844 2698/8398/2842 2704/8394/2848 +f 2706/8399/2849 2528/7592/2673 2705/8400/2850 +f 2707/8401/2851 2528/7592/2673 2706/8402/2849 +f 2476/8403/2620 2707/8404/2851 2706/8405/2849 +f 2684/8348/2828 2707/8406/2851 2476/8407/2620 +f 2467/8408/2611 2684/8348/2828 2476/8409/2620 +f 2685/8349/2829 2684/8348/2828 2467/8410/2611 +f 2468/7344/2612 2708/8411/2852 2470/8412/2614 +f 2709/8413/2853 2708/8414/2852 2468/7344/2612 +f 2459/7325/2601 2709/8415/2853 2468/7344/2612 +f 2710/8416/2854 2709/8417/2853 2459/7325/2601 +f 2457/7327/2603 2710/8416/2854 2459/7325/2601 +f 2372/8418/2516 2710/8416/2854 2457/7327/2603 +f 2711/8419/2855 2683/8347/2827 2685/8349/2829 +f 2712/8420/2856 2683/8347/2827 2711/8421/2855 +f 2713/8422/2857 2712/8423/2856 2711/8424/2855 +f 2714/8425/2858 2712/8426/2856 2713/8422/2857 +f 2715/8427/2859 2714/8425/2858 2713/8422/2857 +f 2708/8428/2852 2714/8425/2858 2715/8427/2859 +f 2688/8429/2832 2690/8360/2834 2689/8430/2833 +f 2691/8362/2835 2690/8360/2834 2688/8429/2832 +f 2716/8431/2860 2691/8362/2835 2688/8429/2832 +f 2471/8432/2615 2691/8362/2835 2716/8433/2860 +f 2479/8434/2624 2471/8435/2615 2716/8436/2860 +f 2712/8437/2856 2681/8344/2825 2683/8347/2827 +f 2380/8438/2524 2681/8344/2825 2712/8439/2856 +f 2714/8425/2858 2380/8440/2524 2712/8441/2856 +f 2379/8442/2525 2380/8443/2524 2714/8425/2858 +f 2708/8428/2852 2379/8444/2525 2714/8425/2858 +f 2709/8445/2853 2379/8446/2525 2708/8447/2852 +f 2717/8448/2861 2379/8449/2525 2709/8450/2853 +f 2718/8451/2862 2717/8452/2861 2709/8453/2853 +f 2719/8454/2863 2717/8455/2861 2718/8456/2862 +f 2722/8457/2864 2721/8458/2865 2720/8459/2866 +f 2723/8460/2867 2721/8458/2865 2722/8457/2864 +f 2457/8461/2603 2723/8460/2867 2722/8457/2864 +f 2458/8462/2602 2723/8460/2867 2457/8461/2603 +f 2722/8463/2864 2372/7123/2516 2457/8464/2603 +f 2356/7100/2500 2372/7123/2516 2722/8463/2864 +f 2720/8465/2866 2356/7100/2500 2722/8463/2864 +f 2355/7099/2499 2356/7100/2500 2720/8465/2866 +f 2685/8466/2829 2724/8467/2868 2711/8468/2855 +f 2725/8469/2869 2724/8467/2868 2685/8466/2829 +f 2467/7343/2611 2725/8469/2869 2685/8466/2829 +f 2466/7342/2610 2725/8469/2869 2467/7343/2611 +f 2687/8470/2831 2522/8471/2664 2520/7597/2666 +f 2701/8472/2845 2522/8473/2664 2687/8474/2831 +f 2378/7129/2522 2701/8475/2845 2687/8476/2831 +f 2377/7126/2519 2701/8477/2845 2378/7129/2522 +f 2696/8478/2840 2703/8479/2847 2698/8480/2842 +f 2702/8481/2846 2703/8482/2847 2696/8483/2840 +f 2538/8484/2682 2702/8485/2846 2696/8486/2840 +f 2526/8487/2670 2702/8488/2846 2538/8489/2682 +f 2704/8394/2848 2726/8490/2870 2700/8381/2844 +f 2727/8491/2871 2726/8492/2870 2704/8394/2848 +f 2377/7126/2519 2727/8493/2871 2704/8394/2848 +f 2375/7128/2521 2727/8494/2871 2377/7126/2519 +f 2694/8367/2837 2359/7101/2501 2357/7103/2503 +f 2474/7361/2618 2359/7101/2501 2694/8367/2837 +f 2695/8369/2839 2474/7361/2618 2694/8367/2837 +f 2697/8495/2841 2474/7361/2618 2695/8369/2839 +f 2728/8496/2872 2382/8497/2526 2381/8498/2523 +f 2383/8499/2527 2382/8500/2526 2728/8501/2872 +f 2374/8502/2518 2383/8503/2527 2728/8504/2872 +f 2727/8505/2871 2729/8506/2873 2726/8507/2870 +f 2692/8508/2836 2729/8509/2873 2727/8510/2871 +f 2375/7128/2521 2692/8511/2836 2727/8512/2871 +f 2473/8513/2619 2730/8514/2874 2478/8515/2622 +f 2699/8516/2843 2730/8517/2874 2473/8518/2619 +f 2700/8519/2844 2732/8520/2875 2731/8521/2876 +f 2726/8522/2870 2732/8520/2875 2700/8519/2844 +f 2384/8523/2528 2720/8465/2866 2733/8524/2877 +f 2355/7099/2499 2720/8465/2866 2384/8525/2528 +f 2373/8526/2517 2710/8416/2854 2372/8418/2516 +f 2718/8527/2862 2710/8416/2854 2373/8526/2517 +f 2386/8528/2530 2716/8529/2860 2688/8429/2832 +f 2385/8530/2529 2716/8531/2860 2386/8532/2530 +f 2374/8533/2518 2718/8534/2862 2373/8535/2517 +f 2728/8536/2872 2718/8537/2862 2374/8538/2518 +f 2713/8539/2857 2734/8540/2878 2715/8541/2859 +f 2735/8542/2879 2734/8540/2878 2713/8539/2857 +f 2717/8543/2861 2381/8544/2523 2379/8545/2525 +f 2719/8546/2863 2381/8547/2523 2717/8548/2861 +f 2470/8549/2614 2715/8550/2859 2734/8551/2878 +f 2708/8552/2852 2715/8550/2859 2470/8549/2614 +f 2735/8553/2879 2711/8554/2855 2724/8555/2868 +f 2713/8556/2857 2711/8557/2855 2735/8558/2879 +f 2529/7591/2672 2682/8346/2826 2680/8342/2824 +f 2528/7592/2673 2682/8346/2826 2529/7591/2672 +f 2707/8559/2851 2682/8346/2826 2528/7592/2673 +f 2684/8348/2828 2682/8346/2826 2707/8560/2851 +f 2385/8561/2529 2733/8562/2877 2479/8563/2624 +f 2384/8564/2528 2733/8565/2877 2385/8566/2529 +f 2731/8567/2876 2699/8568/2843 2700/8569/2844 +f 2730/8570/2874 2699/8571/2843 2731/8572/2876 +f 2479/8573/2624 2736/8574/2880 2480/8575/2623 +f 2733/8576/2877 2736/8577/2880 2479/8578/2624 +f 2473/7362/2619 2697/8579/2841 2699/8580/2843 +f 2474/7361/2618 2697/8581/2841 2473/7362/2619 +f 2728/8582/2872 2719/8583/2863 2718/8584/2862 +f 2381/8585/2523 2719/8586/2863 2728/8587/2872 +f 2733/8588/2877 2721/8458/2865 2736/8589/2880 +f 2720/8459/2866 2721/8458/2865 2733/8590/2877 +f 2737/8591/2881 2726/8592/2870 2729/8593/2873 +f 2732/8594/2875 2726/8595/2870 2737/8596/2881 +f 2729/8597/2873 2461/8598/2606 2737/8599/2881 +f 2692/8600/2836 2461/8601/2606 2729/8602/2873 +f 2706/8603/2849 2366/8604/2510 2476/8605/2620 +f 2365/8606/2511 2366/8607/2510 2706/8608/2849 +f 2479/8609/2624 2716/8610/2860 2385/8611/2529 +f 2686/8350/2830 2348/7092/2494 2370/7119/2514 +f 2472/8612/2616 2691/8362/2835 2471/8613/2615 +f 2710/8416/2854 2718/8614/2862 2709/8615/2853 +f 2702/8616/2846 2526/8617/2670 2524/8618/2668 +f 2538/8619/2682 2696/8620/2840 2537/8621/2683 +f 2357/7103/2503 2693/8368/2838 2694/8367/2837 +f 2738/8622/2882 2693/8368/2838 2357/7103/2503 +f 2358/7102/2502 2738/8622/2882 2357/7103/2503 +f 2739/8623/2883 2738/8622/2882 2358/7102/2502 +f 2740/8624/2884 2739/8623/2883 2358/7102/2502 +f 2559/7697/2703 2739/8623/2883 2740/8624/2884 +f 2741/8625/2885 2559/7697/2703 2740/8624/2884 +f 2558/8626/2702 2559/7697/2703 2741/8627/2885 +f 2556/8628/2700 2558/8629/2702 2741/8630/2885 +f 2693/8368/2838 2539/8631/2681 2537/8632/2683 +f 2546/8633/2690 2539/8634/2681 2693/8368/2838 +f 2738/8622/2882 2546/8635/2690 2693/8368/2838 +f 2550/7648/2694 2546/8636/2690 2738/8622/2882 +f 2739/8623/2883 2550/7648/2694 2738/8622/2882 +f 2552/7653/2696 2550/7648/2694 2739/8623/2883 +f 2559/7697/2703 2552/7653/2696 2739/8623/2883 +f 2367/8637/2509 2741/8638/2885 2740/8624/2884 +f 2742/8639/2886 2741/8640/2885 2367/8641/2509 +f 2365/8642/2511 2742/8643/2886 2367/8644/2509 +f 2705/8645/2850 2742/8646/2886 2365/8647/2511 +f 2706/8648/2849 2705/8649/2850 2365/8650/2511 +f 2742/8651/2886 2556/8652/2700 2741/8653/2885 +f 2518/7581/2662 2556/8654/2700 2742/8655/2886 +f 2705/8656/2850 2518/7581/2662 2742/8657/2886 +f 2369/7115/2513 2740/8624/2884 2358/7102/2502 +f 2367/8658/2509 2740/8624/2884 2369/7115/2513 +f 2516/7579/2660 2705/8659/2850 2528/7592/2673 +f 2518/7581/2662 2705/8660/2850 2516/7579/2660 +s 170 +f 2745/8661/2887 2744/8662/2888 2743/8663/2889 +f 2746/8664/2890 2744/8662/2888 2745/8661/2887 +f 2747/8665/2891 2746/8664/2890 2745/8661/2887 +f 2748/8666/2892 2746/8664/2890 2747/8667/2891 +f 2749/8668/2893 2748/8666/2892 2747/8669/2891 +f 2750/8670/2894 2748/8666/2892 2749/8671/2893 +f 2751/8672/2895 2750/8670/2894 2749/8673/2893 +f 2749/8674/2893 2752/8675/2896 2751/8676/2895 +f 2753/8677/2897 2752/8678/2896 2749/8679/2893 +f 2747/8680/2891 2753/8681/2897 2749/8682/2893 +f 2754/8683/2898 2753/8684/2897 2747/8685/2891 +f 2755/8686/2899 2754/8687/2898 2747/8688/2891 +f 2756/8689/2900 2754/8690/2898 2755/8691/2899 +f 2757/8692/2901 2756/8693/2900 2755/8694/2899 +f 2755/8695/2899 2758/8696/2902 2757/8697/2901 +f 2759/8698/2903 2758/8699/2902 2755/8700/2899 +f 2747/8701/2891 2759/8702/2903 2755/8703/2899 +f 2760/8704/2904 2759/8705/2903 2747/8706/2891 +f 2761/8707/2905 2760/8708/2904 2747/8709/2891 +f 2762/8710/2906 2760/8711/2904 2761/8712/2905 +f 2753/8713/2897 2763/8714/2907 2752/8715/2896 +f 2764/8716/2908 2763/8717/2907 2753/8718/2897 +f 2754/8719/2898 2764/8720/2908 2753/8721/2897 +f 2765/8722/2909 2764/8723/2908 2754/8724/2898 +f 2756/8725/2900 2765/8726/2909 2754/8727/2898 +f 2759/8728/2903 2766/8729/2910 2758/8730/2902 +f 2767/8731/2911 2766/8729/2910 2759/8732/2903 +f 2760/8733/2904 2767/8731/2911 2759/8734/2903 +f 2768/8735/2912 2767/8731/2911 2760/8736/2904 +f 2762/8737/2906 2768/8735/2912 2760/8738/2904 +f 2769/8739/2913 2745/8661/2887 2743/8663/2889 +f 2770/8740/2914 2745/8661/2887 2769/8741/2913 +f 2771/8742/2915 2770/8743/2914 2769/8744/2913 +f 2772/8745/2916 2770/8746/2914 2771/8747/2915 +f 2770/8748/2914 2747/8749/2891 2745/8661/2887 +f 2773/8750/2917 2747/8751/2891 2770/8752/2914 +f 2772/8753/2916 2773/8754/2917 2770/8755/2914 +f 2774/8756/2918 2773/8757/2917 2772/8758/2916 +f 2775/8759/2919 2773/8760/2917 2774/8756/2918 +f 2761/8761/2905 2773/8762/2917 2775/8763/2919 +f 2776/8764/2920 2761/8765/2905 2775/8766/2919 +f 2762/8767/2906 2761/8768/2905 2776/8769/2920 +f 2777/8770/2921 2748/8666/2892 2750/8670/2894 +f 2778/8771/2922 2748/8666/2892 2777/8772/2921 +f 2778/8773/2922 2746/8664/2890 2748/8666/2892 +f 2779/8774/2923 2746/8664/2890 2778/8775/2922 +f 2746/8664/2890 2779/8776/2923 2744/8662/2888 +f 2773/8777/2917 2761/8778/2905 2747/8779/2891 +s 171 +f 2782/8780/2924 2781/8781/2925 2780/8782/2926 +f 2783/8783/2927 2781/8781/2925 2782/8780/2924 +f 2784/8784/2928 2783/8783/2927 2782/8780/2924 +f 2785/8785/2929 2783/8783/2927 2784/8784/2928 +f 2786/8786/2930 2785/8785/2929 2784/8784/2928 +f 2787/8787/2931 2785/8785/2929 2786/8786/2930 +f 2788/8788/2932 2787/8787/2931 2786/8786/2930 +f 2789/8789/2933 2786/8786/2930 2784/8784/2928 +f 2790/8790/2934 2786/8786/2930 2789/8789/2933 +f 2791/8791/2935 2790/8790/2934 2789/8789/2933 +f 2792/8792/2936 2790/8790/2934 2791/8791/2935 +f 2793/8793/2937 2792/8792/2936 2791/8791/2935 +f 2794/8794/2938 2792/8792/2936 2793/8793/2937 +f 2795/8795/2939 2794/8794/2938 2793/8793/2937 +f 2798/8796/2940 2797/8797/2941 2796/8798/2942 +f 2799/8799/2943 2797/8797/2941 2798/8796/2940 +f 2789/8789/2933 2799/8799/2943 2798/8796/2940 +f 2782/8780/2924 2799/8799/2943 2789/8789/2933 +f 2784/8784/2928 2782/8780/2924 2789/8789/2933 +f 2799/8799/2943 2800/8800/2944 2797/8797/2941 +f 2780/8782/2926 2800/8800/2944 2799/8799/2943 +f 2782/8780/2924 2780/8782/2926 2799/8799/2943 +f 2791/8791/2935 2795/8795/2939 2793/8793/2937 +f 2801/8801/2945 2795/8795/2939 2791/8791/2935 +f 2796/8798/2942 2801/8801/2945 2791/8791/2935 +f 2803/8802/2946 2802/8803/2947 2788/8788/2932 +f 2792/8792/2936 2802/8803/2947 2803/8802/2946 +f 2790/8790/2934 2792/8792/2936 2803/8802/2946 +f 2804/8804/2948 2783/8783/2927 2785/8785/2929 +f 2805/8805/2949 2783/8783/2927 2804/8804/2948 +f 2806/8806/2950 2783/8783/2927 2805/8805/2949 +f 2781/8781/2925 2783/8783/2927 2806/8806/2950 +f 2798/8796/2940 2791/8791/2935 2789/8789/2933 +f 2796/8798/2942 2791/8791/2935 2798/8796/2940 +f 2807/8807/2951 2792/8792/2936 2794/8794/2938 +f 2802/8803/2947 2792/8792/2936 2807/8807/2951 +f 2803/8802/2946 2786/8786/2930 2790/8790/2934 +f 2788/8788/2932 2786/8786/2930 2803/8802/2946 +s 174 +f 2810/8808/2952 2808/8809/2953 2809/8810/2954 +f 2811/8811/2955 2810/8808/2952 2809/8810/2954 +f 2812/8812/2956 2810/8808/2952 2811/8811/2955 +f 2813/8813/2957 2812/8812/2956 2811/8811/2955 +f 2814/8814/2958 2812/8812/2956 2813/8813/2957 +f 2815/8815/2959 2814/8814/2958 2813/8813/2957 +f 2816/8816/2960 2814/8814/2958 2815/8815/2959 +f 2817/8817/2961 2812/8812/2956 2814/8814/2958 +f 2818/8818/2962 2817/8817/2961 2814/8814/2958 +f 2819/8819/2963 2817/8817/2961 2818/8818/2962 +f 2820/8820/2964 2819/8819/2963 2818/8818/2962 +f 2821/8821/2965 2819/8819/2963 2820/8820/2964 +f 2822/8822/2966 2821/8821/2965 2820/8820/2964 +f 2823/8823/2967 2821/8821/2965 2822/8822/2966 +f 2826/8824/2968 2824/8825/2969 2825/8826/2970 +f 2827/8827/2971 2826/8824/2968 2825/8826/2970 +f 2817/8817/2961 2826/8824/2968 2827/8827/2971 +f 2810/8808/2952 2817/8817/2961 2827/8827/2971 +f 2812/8812/2956 2817/8817/2961 2810/8808/2952 +f 2827/8827/2971 2825/8826/2970 2828/8828/2972 +f 2808/8809/2953 2827/8827/2971 2828/8828/2972 +f 2810/8808/2952 2827/8827/2971 2808/8809/2953 +f 2819/8819/2963 2821/8821/2965 2823/8823/2967 +f 2829/8829/2973 2819/8819/2963 2823/8823/2967 +f 2824/8825/2969 2819/8819/2963 2829/8829/2973 +f 2831/8830/2974 2816/8816/2960 2830/8831/2975 +f 2820/8820/2964 2831/8830/2974 2830/8831/2975 +f 2818/8818/2962 2831/8830/2974 2820/8820/2964 +f 2832/8832/2976 2813/8813/2957 2811/8811/2955 +f 2833/8833/2977 2832/8832/2976 2811/8811/2955 +f 2834/8834/2978 2833/8833/2977 2811/8811/2955 +f 2809/8810/2954 2834/8834/2978 2811/8811/2955 +f 2826/8824/2968 2817/8817/2961 2819/8819/2963 +f 2824/8825/2969 2826/8824/2968 2819/8819/2963 +f 2835/8835/2979 2822/8822/2966 2820/8820/2964 +f 2830/8831/2975 2835/8835/2979 2820/8820/2964 +f 2831/8830/2974 2818/8818/2962 2814/8814/2958 +f 2816/8816/2960 2831/8830/2974 2814/8814/2958 diff --git a/build/bundle.js b/build/bundle.js new file mode 100644 index 0000000..5abdc3d --- /dev/null +++ b/build/bundle.js @@ -0,0 +1,50727 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; +/******/ +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // identity function for calling harmony imports with the correct context +/******/ __webpack_require__.i = function(value) { return value; }; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 44); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WebGLRenderTargetCube", function() { return WebGLRenderTargetCube; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WebGLRenderTarget", function() { return WebGLRenderTarget; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WebGLRenderer", function() { return WebGLRenderer; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShaderLib", function() { return ShaderLib; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UniformsLib", function() { return UniformsLib; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UniformsUtils", function() { return UniformsUtils; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShaderChunk", function() { return ShaderChunk; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FogExp2", function() { return FogExp2; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Fog", function() { return Fog; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Scene", function() { return Scene; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LensFlare", function() { return LensFlare; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Sprite", function() { return Sprite; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LOD", function() { return LOD; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SkinnedMesh", function() { return SkinnedMesh; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Skeleton", function() { return Skeleton; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Bone", function() { return Bone; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Mesh", function() { return Mesh; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineSegments", function() { return LineSegments; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Line", function() { return Line; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Points", function() { return Points; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Group", function() { return Group; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VideoTexture", function() { return VideoTexture; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DataTexture", function() { return DataTexture; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CompressedTexture", function() { return CompressedTexture; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeTexture", function() { return CubeTexture; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CanvasTexture", function() { return CanvasTexture; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DepthTexture", function() { return DepthTexture; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Texture", function() { return Texture; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CompressedTextureLoader", function() { return CompressedTextureLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DataTextureLoader", function() { return DataTextureLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeTextureLoader", function() { return CubeTextureLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextureLoader", function() { return TextureLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ObjectLoader", function() { return ObjectLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MaterialLoader", function() { return MaterialLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BufferGeometryLoader", function() { return BufferGeometryLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DefaultLoadingManager", function() { return DefaultLoadingManager; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoadingManager", function() { return LoadingManager; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "JSONLoader", function() { return JSONLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImageLoader", function() { return ImageLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FontLoader", function() { return FontLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FileLoader", function() { return FileLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Loader", function() { return Loader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Cache", function() { return Cache; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AudioLoader", function() { return AudioLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpotLightShadow", function() { return SpotLightShadow; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpotLight", function() { return SpotLight; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointLight", function() { return PointLight; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RectAreaLight", function() { return RectAreaLight; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HemisphereLight", function() { return HemisphereLight; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DirectionalLightShadow", function() { return DirectionalLightShadow; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DirectionalLight", function() { return DirectionalLight; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AmbientLight", function() { return AmbientLight; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LightShadow", function() { return LightShadow; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Light", function() { return Light; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StereoCamera", function() { return StereoCamera; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PerspectiveCamera", function() { return PerspectiveCamera; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OrthographicCamera", function() { return OrthographicCamera; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeCamera", function() { return CubeCamera; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Camera", function() { return Camera; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AudioListener", function() { return AudioListener; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PositionalAudio", function() { return PositionalAudio; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AudioContext", function() { return AudioContext; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AudioAnalyser", function() { return AudioAnalyser; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Audio", function() { return Audio; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VectorKeyframeTrack", function() { return VectorKeyframeTrack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StringKeyframeTrack", function() { return StringKeyframeTrack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QuaternionKeyframeTrack", function() { return QuaternionKeyframeTrack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NumberKeyframeTrack", function() { return NumberKeyframeTrack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ColorKeyframeTrack", function() { return ColorKeyframeTrack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BooleanKeyframeTrack", function() { return BooleanKeyframeTrack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PropertyMixer", function() { return PropertyMixer; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PropertyBinding", function() { return PropertyBinding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KeyframeTrack", function() { return KeyframeTrack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationUtils", function() { return AnimationUtils; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationObjectGroup", function() { return AnimationObjectGroup; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationMixer", function() { return AnimationMixer; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationClip", function() { return AnimationClip; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uniform", function() { return Uniform; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InstancedBufferGeometry", function() { return InstancedBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BufferGeometry", function() { return BufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GeometryIdCount", function() { return GeometryIdCount; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Geometry", function() { return Geometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterleavedBufferAttribute", function() { return InterleavedBufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InstancedInterleavedBuffer", function() { return InstancedInterleavedBuffer; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterleavedBuffer", function() { return InterleavedBuffer; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InstancedBufferAttribute", function() { return InstancedBufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Face3", function() { return Face3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Object3D", function() { return Object3D; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Raycaster", function() { return Raycaster; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Layers", function() { return Layers; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EventDispatcher", function() { return EventDispatcher; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Clock", function() { return Clock; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QuaternionLinearInterpolant", function() { return QuaternionLinearInterpolant; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearInterpolant", function() { return LinearInterpolant; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DiscreteInterpolant", function() { return DiscreteInterpolant; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubicInterpolant", function() { return CubicInterpolant; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Interpolant", function() { return Interpolant; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Triangle", function() { return Triangle; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Math", function() { return _Math; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Spherical", function() { return Spherical; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Cylindrical", function() { return Cylindrical; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Plane", function() { return Plane; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Frustum", function() { return Frustum; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Sphere", function() { return Sphere; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Ray", function() { return Ray; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Matrix4", function() { return Matrix4; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Matrix3", function() { return Matrix3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Box3", function() { return Box3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Box2", function() { return Box2; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Line3", function() { return Line3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Euler", function() { return Euler; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector4", function() { return Vector4; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector3", function() { return Vector3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector2", function() { return Vector2; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Quaternion", function() { return Quaternion; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Color", function() { return Color; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MorphBlendMesh", function() { return MorphBlendMesh; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImmediateRenderObject", function() { return ImmediateRenderObject; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VertexNormalsHelper", function() { return VertexNormalsHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpotLightHelper", function() { return SpotLightHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SkeletonHelper", function() { return SkeletonHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointLightHelper", function() { return PointLightHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RectAreaLightHelper", function() { return RectAreaLightHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HemisphereLightHelper", function() { return HemisphereLightHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GridHelper", function() { return GridHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PolarGridHelper", function() { return PolarGridHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FaceNormalsHelper", function() { return FaceNormalsHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DirectionalLightHelper", function() { return DirectionalLightHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CameraHelper", function() { return CameraHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BoxHelper", function() { return BoxHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArrowHelper", function() { return ArrowHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AxisHelper", function() { return AxisHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CatmullRomCurve3", function() { return CatmullRomCurve3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubicBezierCurve3", function() { return CubicBezierCurve3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QuadraticBezierCurve3", function() { return QuadraticBezierCurve3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineCurve3", function() { return LineCurve3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArcCurve", function() { return ArcCurve; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EllipseCurve", function() { return EllipseCurve; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SplineCurve", function() { return SplineCurve; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubicBezierCurve", function() { return CubicBezierCurve; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QuadraticBezierCurve", function() { return QuadraticBezierCurve; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineCurve", function() { return LineCurve; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Shape", function() { return Shape; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Path", function() { return Path; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShapePath", function() { return ShapePath; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Font", function() { return Font; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CurvePath", function() { return CurvePath; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Curve", function() { return Curve; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShapeUtils", function() { return ShapeUtils; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SceneUtils", function() { return SceneUtils; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WireframeGeometry", function() { return WireframeGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParametricGeometry", function() { return ParametricGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParametricBufferGeometry", function() { return ParametricBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TetrahedronGeometry", function() { return TetrahedronGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TetrahedronBufferGeometry", function() { return TetrahedronBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OctahedronGeometry", function() { return OctahedronGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OctahedronBufferGeometry", function() { return OctahedronBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IcosahedronGeometry", function() { return IcosahedronGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IcosahedronBufferGeometry", function() { return IcosahedronBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DodecahedronGeometry", function() { return DodecahedronGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DodecahedronBufferGeometry", function() { return DodecahedronBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PolyhedronGeometry", function() { return PolyhedronGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PolyhedronBufferGeometry", function() { return PolyhedronBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TubeGeometry", function() { return TubeGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TubeBufferGeometry", function() { return TubeBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TorusKnotGeometry", function() { return TorusKnotGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TorusKnotBufferGeometry", function() { return TorusKnotBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TorusGeometry", function() { return TorusGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TorusBufferGeometry", function() { return TorusBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextGeometry", function() { return TextGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SphereGeometry", function() { return SphereGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SphereBufferGeometry", function() { return SphereBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RingGeometry", function() { return RingGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RingBufferGeometry", function() { return RingBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlaneGeometry", function() { return PlaneGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlaneBufferGeometry", function() { return PlaneBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LatheGeometry", function() { return LatheGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LatheBufferGeometry", function() { return LatheBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShapeGeometry", function() { return ShapeGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShapeBufferGeometry", function() { return ShapeBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ExtrudeGeometry", function() { return ExtrudeGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EdgesGeometry", function() { return EdgesGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConeGeometry", function() { return ConeGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConeBufferGeometry", function() { return ConeBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CylinderGeometry", function() { return CylinderGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CylinderBufferGeometry", function() { return CylinderBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CircleGeometry", function() { return CircleGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CircleBufferGeometry", function() { return CircleBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BoxGeometry", function() { return BoxGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BoxBufferGeometry", function() { return BoxBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShadowMaterial", function() { return ShadowMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpriteMaterial", function() { return SpriteMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RawShaderMaterial", function() { return RawShaderMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShaderMaterial", function() { return ShaderMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointsMaterial", function() { return PointsMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiMaterial", function() { return MultiMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshPhysicalMaterial", function() { return MeshPhysicalMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshStandardMaterial", function() { return MeshStandardMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshPhongMaterial", function() { return MeshPhongMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshToonMaterial", function() { return MeshToonMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshNormalMaterial", function() { return MeshNormalMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshLambertMaterial", function() { return MeshLambertMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshDepthMaterial", function() { return MeshDepthMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshBasicMaterial", function() { return MeshBasicMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineDashedMaterial", function() { return LineDashedMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineBasicMaterial", function() { return LineBasicMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Material", function() { return Material; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float64BufferAttribute", function() { return Float64BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float32BufferAttribute", function() { return Float32BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint32BufferAttribute", function() { return Uint32BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int32BufferAttribute", function() { return Int32BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint16BufferAttribute", function() { return Uint16BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int16BufferAttribute", function() { return Int16BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint8ClampedBufferAttribute", function() { return Uint8ClampedBufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint8BufferAttribute", function() { return Uint8BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int8BufferAttribute", function() { return Int8BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BufferAttribute", function() { return BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "REVISION", function() { return REVISION; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MOUSE", function() { return MOUSE; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CullFaceNone", function() { return CullFaceNone; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CullFaceBack", function() { return CullFaceBack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CullFaceFront", function() { return CullFaceFront; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CullFaceFrontBack", function() { return CullFaceFrontBack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FrontFaceDirectionCW", function() { return FrontFaceDirectionCW; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FrontFaceDirectionCCW", function() { return FrontFaceDirectionCCW; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BasicShadowMap", function() { return BasicShadowMap; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PCFShadowMap", function() { return PCFShadowMap; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PCFSoftShadowMap", function() { return PCFSoftShadowMap; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FrontSide", function() { return FrontSide; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BackSide", function() { return BackSide; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DoubleSide", function() { return DoubleSide; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FlatShading", function() { return FlatShading; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SmoothShading", function() { return SmoothShading; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NoColors", function() { return NoColors; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FaceColors", function() { return FaceColors; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VertexColors", function() { return VertexColors; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NoBlending", function() { return NoBlending; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NormalBlending", function() { return NormalBlending; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdditiveBlending", function() { return AdditiveBlending; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SubtractiveBlending", function() { return SubtractiveBlending; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiplyBlending", function() { return MultiplyBlending; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CustomBlending", function() { return CustomBlending; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AddEquation", function() { return AddEquation; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SubtractEquation", function() { return SubtractEquation; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ReverseSubtractEquation", function() { return ReverseSubtractEquation; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MinEquation", function() { return MinEquation; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MaxEquation", function() { return MaxEquation; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ZeroFactor", function() { return ZeroFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneFactor", function() { return OneFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SrcColorFactor", function() { return SrcColorFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneMinusSrcColorFactor", function() { return OneMinusSrcColorFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SrcAlphaFactor", function() { return SrcAlphaFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneMinusSrcAlphaFactor", function() { return OneMinusSrcAlphaFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DstAlphaFactor", function() { return DstAlphaFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneMinusDstAlphaFactor", function() { return OneMinusDstAlphaFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DstColorFactor", function() { return DstColorFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneMinusDstColorFactor", function() { return OneMinusDstColorFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SrcAlphaSaturateFactor", function() { return SrcAlphaSaturateFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NeverDepth", function() { return NeverDepth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AlwaysDepth", function() { return AlwaysDepth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LessDepth", function() { return LessDepth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LessEqualDepth", function() { return LessEqualDepth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EqualDepth", function() { return EqualDepth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GreaterEqualDepth", function() { return GreaterEqualDepth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GreaterDepth", function() { return GreaterDepth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NotEqualDepth", function() { return NotEqualDepth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiplyOperation", function() { return MultiplyOperation; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MixOperation", function() { return MixOperation; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AddOperation", function() { return AddOperation; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NoToneMapping", function() { return NoToneMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearToneMapping", function() { return LinearToneMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ReinhardToneMapping", function() { return ReinhardToneMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uncharted2ToneMapping", function() { return Uncharted2ToneMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CineonToneMapping", function() { return CineonToneMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UVMapping", function() { return UVMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeReflectionMapping", function() { return CubeReflectionMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeRefractionMapping", function() { return CubeRefractionMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EquirectangularReflectionMapping", function() { return EquirectangularReflectionMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EquirectangularRefractionMapping", function() { return EquirectangularRefractionMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SphericalReflectionMapping", function() { return SphericalReflectionMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeUVReflectionMapping", function() { return CubeUVReflectionMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeUVRefractionMapping", function() { return CubeUVRefractionMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RepeatWrapping", function() { return RepeatWrapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ClampToEdgeWrapping", function() { return ClampToEdgeWrapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MirroredRepeatWrapping", function() { return MirroredRepeatWrapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NearestFilter", function() { return NearestFilter; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NearestMipMapNearestFilter", function() { return NearestMipMapNearestFilter; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NearestMipMapLinearFilter", function() { return NearestMipMapLinearFilter; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearFilter", function() { return LinearFilter; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearMipMapNearestFilter", function() { return LinearMipMapNearestFilter; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearMipMapLinearFilter", function() { return LinearMipMapLinearFilter; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedByteType", function() { return UnsignedByteType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ByteType", function() { return ByteType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShortType", function() { return ShortType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedShortType", function() { return UnsignedShortType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IntType", function() { return IntType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedIntType", function() { return UnsignedIntType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatType", function() { return FloatType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HalfFloatType", function() { return HalfFloatType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedShort4444Type", function() { return UnsignedShort4444Type; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedShort5551Type", function() { return UnsignedShort5551Type; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedShort565Type", function() { return UnsignedShort565Type; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedInt248Type", function() { return UnsignedInt248Type; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AlphaFormat", function() { return AlphaFormat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBFormat", function() { return RGBFormat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBAFormat", function() { return RGBAFormat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LuminanceFormat", function() { return LuminanceFormat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LuminanceAlphaFormat", function() { return LuminanceAlphaFormat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBEFormat", function() { return RGBEFormat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DepthFormat", function() { return DepthFormat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DepthStencilFormat", function() { return DepthStencilFormat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGB_S3TC_DXT1_Format", function() { return RGB_S3TC_DXT1_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_S3TC_DXT1_Format", function() { return RGBA_S3TC_DXT1_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_S3TC_DXT3_Format", function() { return RGBA_S3TC_DXT3_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_S3TC_DXT5_Format", function() { return RGBA_S3TC_DXT5_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGB_PVRTC_4BPPV1_Format", function() { return RGB_PVRTC_4BPPV1_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGB_PVRTC_2BPPV1_Format", function() { return RGB_PVRTC_2BPPV1_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_PVRTC_4BPPV1_Format", function() { return RGBA_PVRTC_4BPPV1_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_PVRTC_2BPPV1_Format", function() { return RGBA_PVRTC_2BPPV1_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGB_ETC1_Format", function() { return RGB_ETC1_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoopOnce", function() { return LoopOnce; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoopRepeat", function() { return LoopRepeat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoopPingPong", function() { return LoopPingPong; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterpolateDiscrete", function() { return InterpolateDiscrete; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterpolateLinear", function() { return InterpolateLinear; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterpolateSmooth", function() { return InterpolateSmooth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ZeroCurvatureEnding", function() { return ZeroCurvatureEnding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ZeroSlopeEnding", function() { return ZeroSlopeEnding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WrapAroundEnding", function() { return WrapAroundEnding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TrianglesDrawMode", function() { return TrianglesDrawMode; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TriangleStripDrawMode", function() { return TriangleStripDrawMode; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TriangleFanDrawMode", function() { return TriangleFanDrawMode; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearEncoding", function() { return LinearEncoding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sRGBEncoding", function() { return sRGBEncoding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GammaEncoding", function() { return GammaEncoding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBEEncoding", function() { return RGBEEncoding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LogLuvEncoding", function() { return LogLuvEncoding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBM7Encoding", function() { return RGBM7Encoding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBM16Encoding", function() { return RGBM16Encoding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBDEncoding", function() { return RGBDEncoding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BasicDepthPacking", function() { return BasicDepthPacking; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBADepthPacking", function() { return RGBADepthPacking; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeGeometry", function() { return BoxGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Face4", function() { return Face4; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineStrip", function() { return LineStrip; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinePieces", function() { return LinePieces; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshFaceMaterial", function() { return MeshFaceMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointCloud", function() { return PointCloud; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Particle", function() { return Particle; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParticleSystem", function() { return ParticleSystem; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointCloudMaterial", function() { return PointCloudMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParticleBasicMaterial", function() { return ParticleBasicMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParticleSystemMaterial", function() { return ParticleSystemMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vertex", function() { return Vertex; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DynamicBufferAttribute", function() { return DynamicBufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int8Attribute", function() { return Int8Attribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint8Attribute", function() { return Uint8Attribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint8ClampedAttribute", function() { return Uint8ClampedAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int16Attribute", function() { return Int16Attribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint16Attribute", function() { return Uint16Attribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int32Attribute", function() { return Int32Attribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint32Attribute", function() { return Uint32Attribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float32Attribute", function() { return Float32Attribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float64Attribute", function() { return Float64Attribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ClosedSplineCurve3", function() { return ClosedSplineCurve3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SplineCurve3", function() { return SplineCurve3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Spline", function() { return Spline; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BoundingBoxHelper", function() { return BoundingBoxHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EdgesHelper", function() { return EdgesHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WireframeHelper", function() { return WireframeHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "XHRLoader", function() { return XHRLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BinaryTextureLoader", function() { return BinaryTextureLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GeometryUtils", function() { return GeometryUtils; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImageUtils", function() { return ImageUtils; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Projector", function() { return Projector; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CanvasRenderer", function() { return CanvasRenderer; }); +// Polyfills + +if ( Number.EPSILON === undefined ) { + + Number.EPSILON = Math.pow( 2, - 52 ); + +} + +// + +if ( Math.sign === undefined ) { + + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign + + Math.sign = function ( x ) { + + return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : + x; + + }; + +} + +if ( Function.prototype.name === undefined ) { + + // Missing in IE9-11. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name + + Object.defineProperty( Function.prototype, 'name', { + + get: function () { + + return this.toString().match( /^\s*function\s*([^\(\s]*)/ )[ 1 ]; + + } + + } ); + +} + +if ( Object.assign === undefined ) { + + // Missing in IE. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign + + ( function () { + + Object.assign = function ( target ) { + + 'use strict'; + + if ( target === undefined || target === null ) { + + throw new TypeError( 'Cannot convert undefined or null to object' ); + + } + + var output = Object( target ); + + for ( var index = 1; index < arguments.length; index ++ ) { + + var source = arguments[ index ]; + + if ( source !== undefined && source !== null ) { + + for ( var nextKey in source ) { + + if ( Object.prototype.hasOwnProperty.call( source, nextKey ) ) { + + output[ nextKey ] = source[ nextKey ]; + + } + + } + + } + + } + + return output; + + }; + + } )(); + +} + +/** + * https://github.com/mrdoob/eventdispatcher.js/ + */ + +function EventDispatcher() {} + +EventDispatcher.prototype = { + + addEventListener: function ( type, listener ) { + + if ( this._listeners === undefined ) this._listeners = {}; + + var listeners = this._listeners; + + if ( listeners[ type ] === undefined ) { + + listeners[ type ] = []; + + } + + if ( listeners[ type ].indexOf( listener ) === - 1 ) { + + listeners[ type ].push( listener ); + + } + + }, + + hasEventListener: function ( type, listener ) { + + if ( this._listeners === undefined ) return false; + + var listeners = this._listeners; + + return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1; + + }, + + removeEventListener: function ( type, listener ) { + + if ( this._listeners === undefined ) return; + + var listeners = this._listeners; + var listenerArray = listeners[ type ]; + + if ( listenerArray !== undefined ) { + + var index = listenerArray.indexOf( listener ); + + if ( index !== - 1 ) { + + listenerArray.splice( index, 1 ); + + } + + } + + }, + + dispatchEvent: function ( event ) { + + if ( this._listeners === undefined ) return; + + var listeners = this._listeners; + var listenerArray = listeners[ event.type ]; + + if ( listenerArray !== undefined ) { + + event.target = this; + + var array = [], i = 0; + var length = listenerArray.length; + + for ( i = 0; i < length; i ++ ) { + + array[ i ] = listenerArray[ i ]; + + } + + for ( i = 0; i < length; i ++ ) { + + array[ i ].call( this, event ); + + } + + } + + } + +}; + +var REVISION = '84'; +var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }; +var CullFaceNone = 0; +var CullFaceBack = 1; +var CullFaceFront = 2; +var CullFaceFrontBack = 3; +var FrontFaceDirectionCW = 0; +var FrontFaceDirectionCCW = 1; +var BasicShadowMap = 0; +var PCFShadowMap = 1; +var PCFSoftShadowMap = 2; +var FrontSide = 0; +var BackSide = 1; +var DoubleSide = 2; +var FlatShading = 1; +var SmoothShading = 2; +var NoColors = 0; +var FaceColors = 1; +var VertexColors = 2; +var NoBlending = 0; +var NormalBlending = 1; +var AdditiveBlending = 2; +var SubtractiveBlending = 3; +var MultiplyBlending = 4; +var CustomBlending = 5; +var AddEquation = 100; +var SubtractEquation = 101; +var ReverseSubtractEquation = 102; +var MinEquation = 103; +var MaxEquation = 104; +var ZeroFactor = 200; +var OneFactor = 201; +var SrcColorFactor = 202; +var OneMinusSrcColorFactor = 203; +var SrcAlphaFactor = 204; +var OneMinusSrcAlphaFactor = 205; +var DstAlphaFactor = 206; +var OneMinusDstAlphaFactor = 207; +var DstColorFactor = 208; +var OneMinusDstColorFactor = 209; +var SrcAlphaSaturateFactor = 210; +var NeverDepth = 0; +var AlwaysDepth = 1; +var LessDepth = 2; +var LessEqualDepth = 3; +var EqualDepth = 4; +var GreaterEqualDepth = 5; +var GreaterDepth = 6; +var NotEqualDepth = 7; +var MultiplyOperation = 0; +var MixOperation = 1; +var AddOperation = 2; +var NoToneMapping = 0; +var LinearToneMapping = 1; +var ReinhardToneMapping = 2; +var Uncharted2ToneMapping = 3; +var CineonToneMapping = 4; +var UVMapping = 300; +var CubeReflectionMapping = 301; +var CubeRefractionMapping = 302; +var EquirectangularReflectionMapping = 303; +var EquirectangularRefractionMapping = 304; +var SphericalReflectionMapping = 305; +var CubeUVReflectionMapping = 306; +var CubeUVRefractionMapping = 307; +var RepeatWrapping = 1000; +var ClampToEdgeWrapping = 1001; +var MirroredRepeatWrapping = 1002; +var NearestFilter = 1003; +var NearestMipMapNearestFilter = 1004; +var NearestMipMapLinearFilter = 1005; +var LinearFilter = 1006; +var LinearMipMapNearestFilter = 1007; +var LinearMipMapLinearFilter = 1008; +var UnsignedByteType = 1009; +var ByteType = 1010; +var ShortType = 1011; +var UnsignedShortType = 1012; +var IntType = 1013; +var UnsignedIntType = 1014; +var FloatType = 1015; +var HalfFloatType = 1016; +var UnsignedShort4444Type = 1017; +var UnsignedShort5551Type = 1018; +var UnsignedShort565Type = 1019; +var UnsignedInt248Type = 1020; +var AlphaFormat = 1021; +var RGBFormat = 1022; +var RGBAFormat = 1023; +var LuminanceFormat = 1024; +var LuminanceAlphaFormat = 1025; +var RGBEFormat = RGBAFormat; +var DepthFormat = 1026; +var DepthStencilFormat = 1027; +var RGB_S3TC_DXT1_Format = 2001; +var RGBA_S3TC_DXT1_Format = 2002; +var RGBA_S3TC_DXT3_Format = 2003; +var RGBA_S3TC_DXT5_Format = 2004; +var RGB_PVRTC_4BPPV1_Format = 2100; +var RGB_PVRTC_2BPPV1_Format = 2101; +var RGBA_PVRTC_4BPPV1_Format = 2102; +var RGBA_PVRTC_2BPPV1_Format = 2103; +var RGB_ETC1_Format = 2151; +var LoopOnce = 2200; +var LoopRepeat = 2201; +var LoopPingPong = 2202; +var InterpolateDiscrete = 2300; +var InterpolateLinear = 2301; +var InterpolateSmooth = 2302; +var ZeroCurvatureEnding = 2400; +var ZeroSlopeEnding = 2401; +var WrapAroundEnding = 2402; +var TrianglesDrawMode = 0; +var TriangleStripDrawMode = 1; +var TriangleFanDrawMode = 2; +var LinearEncoding = 3000; +var sRGBEncoding = 3001; +var GammaEncoding = 3007; +var RGBEEncoding = 3002; +var LogLuvEncoding = 3003; +var RGBM7Encoding = 3004; +var RGBM16Encoding = 3005; +var RGBDEncoding = 3006; +var BasicDepthPacking = 3200; +var RGBADepthPacking = 3201; + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ + +var _Math = { + + DEG2RAD: Math.PI / 180, + RAD2DEG: 180 / Math.PI, + + generateUUID: function () { + + // http://www.broofa.com/Tools/Math.uuid.htm + + var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' ); + var uuid = new Array( 36 ); + var rnd = 0, r; + + return function generateUUID() { + + for ( var i = 0; i < 36; i ++ ) { + + if ( i === 8 || i === 13 || i === 18 || i === 23 ) { + + uuid[ i ] = '-'; + + } else if ( i === 14 ) { + + uuid[ i ] = '4'; + + } else { + + if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0; + r = rnd & 0xf; + rnd = rnd >> 4; + uuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ]; + + } + + } + + return uuid.join( '' ); + + }; + + }(), + + clamp: function ( value, min, max ) { + + return Math.max( min, Math.min( max, value ) ); + + }, + + // compute euclidian modulo of m % n + // https://en.wikipedia.org/wiki/Modulo_operation + + euclideanModulo: function ( n, m ) { + + return ( ( n % m ) + m ) % m; + + }, + + // Linear mapping from range to range + + mapLinear: function ( x, a1, a2, b1, b2 ) { + + return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); + + }, + + // https://en.wikipedia.org/wiki/Linear_interpolation + + lerp: function ( x, y, t ) { + + return ( 1 - t ) * x + t * y; + + }, + + // http://en.wikipedia.org/wiki/Smoothstep + + smoothstep: function ( x, min, max ) { + + if ( x <= min ) return 0; + if ( x >= max ) return 1; + + x = ( x - min ) / ( max - min ); + + return x * x * ( 3 - 2 * x ); + + }, + + smootherstep: function ( x, min, max ) { + + if ( x <= min ) return 0; + if ( x >= max ) return 1; + + x = ( x - min ) / ( max - min ); + + return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); + + }, + + // Random integer from interval + + randInt: function ( low, high ) { + + return low + Math.floor( Math.random() * ( high - low + 1 ) ); + + }, + + // Random float from interval + + randFloat: function ( low, high ) { + + return low + Math.random() * ( high - low ); + + }, + + // Random float from <-range/2, range/2> interval + + randFloatSpread: function ( range ) { + + return range * ( 0.5 - Math.random() ); + + }, + + degToRad: function ( degrees ) { + + return degrees * _Math.DEG2RAD; + + }, + + radToDeg: function ( radians ) { + + return radians * _Math.RAD2DEG; + + }, + + isPowerOfTwo: function ( value ) { + + return ( value & ( value - 1 ) ) === 0 && value !== 0; + + }, + + nearestPowerOfTwo: function ( value ) { + + return Math.pow( 2, Math.round( Math.log( value ) / Math.LN2 ) ); + + }, + + nextPowerOfTwo: function ( value ) { + + value --; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; + value ++; + + return value; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author philogb / http://blog.thejit.org/ + * @author egraether / http://egraether.com/ + * @author zz85 / http://www.lab4games.net/zz85/blog + */ + +function Vector2( x, y ) { + + this.x = x || 0; + this.y = y || 0; + +} + +Vector2.prototype = { + + constructor: Vector2, + + isVector2: true, + + get width() { + + return this.x; + + }, + + set width( value ) { + + this.x = value; + + }, + + get height() { + + return this.y; + + }, + + set height( value ) { + + this.y = value; + + }, + + // + + set: function ( x, y ) { + + this.x = x; + this.y = y; + + return this; + + }, + + setScalar: function ( scalar ) { + + this.x = scalar; + this.y = scalar; + + return this; + + }, + + setX: function ( x ) { + + this.x = x; + + return this; + + }, + + setY: function ( y ) { + + this.y = y; + + return this; + + }, + + setComponent: function ( index, value ) { + + switch ( index ) { + + case 0: this.x = value; break; + case 1: this.y = value; break; + default: throw new Error( 'index is out of range: ' + index ); + + } + + return this; + + }, + + getComponent: function ( index ) { + + switch ( index ) { + + case 0: return this.x; + case 1: return this.y; + default: throw new Error( 'index is out of range: ' + index ); + + } + + }, + + clone: function () { + + return new this.constructor( this.x, this.y ); + + }, + + copy: function ( v ) { + + this.x = v.x; + this.y = v.y; + + return this; + + }, + + add: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + return this.addVectors( v, w ); + + } + + this.x += v.x; + this.y += v.y; + + return this; + + }, + + addScalar: function ( s ) { + + this.x += s; + this.y += s; + + return this; + + }, + + addVectors: function ( a, b ) { + + this.x = a.x + b.x; + this.y = a.y + b.y; + + return this; + + }, + + addScaledVector: function ( v, s ) { + + this.x += v.x * s; + this.y += v.y * s; + + return this; + + }, + + sub: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + return this.subVectors( v, w ); + + } + + this.x -= v.x; + this.y -= v.y; + + return this; + + }, + + subScalar: function ( s ) { + + this.x -= s; + this.y -= s; + + return this; + + }, + + subVectors: function ( a, b ) { + + this.x = a.x - b.x; + this.y = a.y - b.y; + + return this; + + }, + + multiply: function ( v ) { + + this.x *= v.x; + this.y *= v.y; + + return this; + + }, + + multiplyScalar: function ( scalar ) { + + if ( isFinite( scalar ) ) { + + this.x *= scalar; + this.y *= scalar; + + } else { + + this.x = 0; + this.y = 0; + + } + + return this; + + }, + + divide: function ( v ) { + + this.x /= v.x; + this.y /= v.y; + + return this; + + }, + + divideScalar: function ( scalar ) { + + return this.multiplyScalar( 1 / scalar ); + + }, + + min: function ( v ) { + + this.x = Math.min( this.x, v.x ); + this.y = Math.min( this.y, v.y ); + + return this; + + }, + + max: function ( v ) { + + this.x = Math.max( this.x, v.x ); + this.y = Math.max( this.y, v.y ); + + return this; + + }, + + clamp: function ( min, max ) { + + // This function assumes min < max, if this assumption isn't true it will not operate correctly + + this.x = Math.max( min.x, Math.min( max.x, this.x ) ); + this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + + return this; + + }, + + clampScalar: function () { + + var min, max; + + return function clampScalar( minVal, maxVal ) { + + if ( min === undefined ) { + + min = new Vector2(); + max = new Vector2(); + + } + + min.set( minVal, minVal ); + max.set( maxVal, maxVal ); + + return this.clamp( min, max ); + + }; + + }(), + + clampLength: function ( min, max ) { + + var length = this.length(); + + return this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length ); + + }, + + floor: function () { + + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + + return this; + + }, + + ceil: function () { + + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + + return this; + + }, + + round: function () { + + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + + return this; + + }, + + roundToZero: function () { + + this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); + this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); + + return this; + + }, + + negate: function () { + + this.x = - this.x; + this.y = - this.y; + + return this; + + }, + + dot: function ( v ) { + + return this.x * v.x + this.y * v.y; + + }, + + lengthSq: function () { + + return this.x * this.x + this.y * this.y; + + }, + + length: function () { + + return Math.sqrt( this.x * this.x + this.y * this.y ); + + }, + + lengthManhattan: function() { + + return Math.abs( this.x ) + Math.abs( this.y ); + + }, + + normalize: function () { + + return this.divideScalar( this.length() ); + + }, + + angle: function () { + + // computes the angle in radians with respect to the positive x-axis + + var angle = Math.atan2( this.y, this.x ); + + if ( angle < 0 ) angle += 2 * Math.PI; + + return angle; + + }, + + distanceTo: function ( v ) { + + return Math.sqrt( this.distanceToSquared( v ) ); + + }, + + distanceToSquared: function ( v ) { + + var dx = this.x - v.x, dy = this.y - v.y; + return dx * dx + dy * dy; + + }, + + distanceToManhattan: function ( v ) { + + return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ); + + }, + + setLength: function ( length ) { + + return this.multiplyScalar( length / this.length() ); + + }, + + lerp: function ( v, alpha ) { + + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + + return this; + + }, + + lerpVectors: function ( v1, v2, alpha ) { + + return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); + + }, + + equals: function ( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) ); + + }, + + fromArray: function ( array, offset ) { + + if ( offset === undefined ) offset = 0; + + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + + return this; + + }, + + toArray: function ( array, offset ) { + + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; + + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + + return array; + + }, + + fromBufferAttribute: function ( attribute, index, offset ) { + + if ( offset !== undefined ) { + + console.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' ); + + } + + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); + + return this; + + }, + + rotateAround: function ( center, angle ) { + + var c = Math.cos( angle ), s = Math.sin( angle ); + + var x = this.x - center.x; + var y = this.y - center.y; + + this.x = x * c - y * s + center.x; + this.y = x * s + y * c + center.y; + + return this; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author szimek / https://github.com/szimek/ + */ + +var textureId = 0; + +function Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { + + Object.defineProperty( this, 'id', { value: textureId ++ } ); + + this.uuid = _Math.generateUUID(); + + this.name = ''; + + this.image = image !== undefined ? image : Texture.DEFAULT_IMAGE; + this.mipmaps = []; + + this.mapping = mapping !== undefined ? mapping : Texture.DEFAULT_MAPPING; + + this.wrapS = wrapS !== undefined ? wrapS : ClampToEdgeWrapping; + this.wrapT = wrapT !== undefined ? wrapT : ClampToEdgeWrapping; + + this.magFilter = magFilter !== undefined ? magFilter : LinearFilter; + this.minFilter = minFilter !== undefined ? minFilter : LinearMipMapLinearFilter; + + this.anisotropy = anisotropy !== undefined ? anisotropy : 1; + + this.format = format !== undefined ? format : RGBAFormat; + this.type = type !== undefined ? type : UnsignedByteType; + + this.offset = new Vector2( 0, 0 ); + this.repeat = new Vector2( 1, 1 ); + + this.generateMipmaps = true; + this.premultiplyAlpha = false; + this.flipY = true; + this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) + + + // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap. + // + // Also changing the encoding after already used by a Material will not automatically make the Material + // update. You need to explicitly call Material.needsUpdate to trigger it to recompile. + this.encoding = encoding !== undefined ? encoding : LinearEncoding; + + this.version = 0; + this.onUpdate = null; + +} + +Texture.DEFAULT_IMAGE = undefined; +Texture.DEFAULT_MAPPING = UVMapping; + +Texture.prototype = { + + constructor: Texture, + + isTexture: true, + + set needsUpdate( value ) { + + if ( value === true ) this.version ++; + + }, + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + copy: function ( source ) { + + this.image = source.image; + this.mipmaps = source.mipmaps.slice( 0 ); + + this.mapping = source.mapping; + + this.wrapS = source.wrapS; + this.wrapT = source.wrapT; + + this.magFilter = source.magFilter; + this.minFilter = source.minFilter; + + this.anisotropy = source.anisotropy; + + this.format = source.format; + this.type = source.type; + + this.offset.copy( source.offset ); + this.repeat.copy( source.repeat ); + + this.generateMipmaps = source.generateMipmaps; + this.premultiplyAlpha = source.premultiplyAlpha; + this.flipY = source.flipY; + this.unpackAlignment = source.unpackAlignment; + this.encoding = source.encoding; + + return this; + + }, + + toJSON: function ( meta ) { + + if ( meta.textures[ this.uuid ] !== undefined ) { + + return meta.textures[ this.uuid ]; + + } + + function getDataURL( image ) { + + var canvas; + + if ( image.toDataURL !== undefined ) { + + canvas = image; + + } else { + + canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); + canvas.width = image.width; + canvas.height = image.height; + + canvas.getContext( '2d' ).drawImage( image, 0, 0, image.width, image.height ); + + } + + if ( canvas.width > 2048 || canvas.height > 2048 ) { + + return canvas.toDataURL( 'image/jpeg', 0.6 ); + + } else { + + return canvas.toDataURL( 'image/png' ); + + } + + } + + var output = { + metadata: { + version: 4.4, + type: 'Texture', + generator: 'Texture.toJSON' + }, + + uuid: this.uuid, + name: this.name, + + mapping: this.mapping, + + repeat: [ this.repeat.x, this.repeat.y ], + offset: [ this.offset.x, this.offset.y ], + wrap: [ this.wrapS, this.wrapT ], + + minFilter: this.minFilter, + magFilter: this.magFilter, + anisotropy: this.anisotropy, + + flipY: this.flipY + }; + + if ( this.image !== undefined ) { + + // TODO: Move to THREE.Image + + var image = this.image; + + if ( image.uuid === undefined ) { + + image.uuid = _Math.generateUUID(); // UGH + + } + + if ( meta.images[ image.uuid ] === undefined ) { + + meta.images[ image.uuid ] = { + uuid: image.uuid, + url: getDataURL( image ) + }; + + } + + output.image = image.uuid; + + } + + meta.textures[ this.uuid ] = output; + + return output; + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + }, + + transformUv: function ( uv ) { + + if ( this.mapping !== UVMapping ) return; + + uv.multiply( this.repeat ); + uv.add( this.offset ); + + if ( uv.x < 0 || uv.x > 1 ) { + + switch ( this.wrapS ) { + + case RepeatWrapping: + + uv.x = uv.x - Math.floor( uv.x ); + break; + + case ClampToEdgeWrapping: + + uv.x = uv.x < 0 ? 0 : 1; + break; + + case MirroredRepeatWrapping: + + if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { + + uv.x = Math.ceil( uv.x ) - uv.x; + + } else { + + uv.x = uv.x - Math.floor( uv.x ); + + } + break; + + } + + } + + if ( uv.y < 0 || uv.y > 1 ) { + + switch ( this.wrapT ) { + + case RepeatWrapping: + + uv.y = uv.y - Math.floor( uv.y ); + break; + + case ClampToEdgeWrapping: + + uv.y = uv.y < 0 ? 0 : 1; + break; + + case MirroredRepeatWrapping: + + if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { + + uv.y = Math.ceil( uv.y ) - uv.y; + + } else { + + uv.y = uv.y - Math.floor( uv.y ); + + } + break; + + } + + } + + if ( this.flipY ) { + + uv.y = 1 - uv.y; + + } + + } + +}; + +Object.assign( Texture.prototype, EventDispatcher.prototype ); + +/** + * @author supereggbert / http://www.paulbrunt.co.uk/ + * @author philogb / http://blog.thejit.org/ + * @author mikael emtinger / http://gomo.se/ + * @author egraether / http://egraether.com/ + * @author WestLangley / http://github.com/WestLangley + */ + +function Vector4( x, y, z, w ) { + + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; + this.w = ( w !== undefined ) ? w : 1; + +} + +Vector4.prototype = { + + constructor: Vector4, + + isVector4: true, + + set: function ( x, y, z, w ) { + + this.x = x; + this.y = y; + this.z = z; + this.w = w; + + return this; + + }, + + setScalar: function ( scalar ) { + + this.x = scalar; + this.y = scalar; + this.z = scalar; + this.w = scalar; + + return this; + + }, + + setX: function ( x ) { + + this.x = x; + + return this; + + }, + + setY: function ( y ) { + + this.y = y; + + return this; + + }, + + setZ: function ( z ) { + + this.z = z; + + return this; + + }, + + setW: function ( w ) { + + this.w = w; + + return this; + + }, + + setComponent: function ( index, value ) { + + switch ( index ) { + + case 0: this.x = value; break; + case 1: this.y = value; break; + case 2: this.z = value; break; + case 3: this.w = value; break; + default: throw new Error( 'index is out of range: ' + index ); + + } + + return this; + + }, + + getComponent: function ( index ) { + + switch ( index ) { + + case 0: return this.x; + case 1: return this.y; + case 2: return this.z; + case 3: return this.w; + default: throw new Error( 'index is out of range: ' + index ); + + } + + }, + + clone: function () { + + return new this.constructor( this.x, this.y, this.z, this.w ); + + }, + + copy: function ( v ) { + + this.x = v.x; + this.y = v.y; + this.z = v.z; + this.w = ( v.w !== undefined ) ? v.w : 1; + + return this; + + }, + + add: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + return this.addVectors( v, w ); + + } + + this.x += v.x; + this.y += v.y; + this.z += v.z; + this.w += v.w; + + return this; + + }, + + addScalar: function ( s ) { + + this.x += s; + this.y += s; + this.z += s; + this.w += s; + + return this; + + }, + + addVectors: function ( a, b ) { + + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; + this.w = a.w + b.w; + + return this; + + }, + + addScaledVector: function ( v, s ) { + + this.x += v.x * s; + this.y += v.y * s; + this.z += v.z * s; + this.w += v.w * s; + + return this; + + }, + + sub: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + return this.subVectors( v, w ); + + } + + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + this.w -= v.w; + + return this; + + }, + + subScalar: function ( s ) { + + this.x -= s; + this.y -= s; + this.z -= s; + this.w -= s; + + return this; + + }, + + subVectors: function ( a, b ) { + + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; + this.w = a.w - b.w; + + return this; + + }, + + multiplyScalar: function ( scalar ) { + + if ( isFinite( scalar ) ) { + + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + this.w *= scalar; + + } else { + + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 0; + + } + + return this; + + }, + + applyMatrix4: function ( m ) { + + var x = this.x, y = this.y, z = this.z, w = this.w; + var e = m.elements; + + this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w; + this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w; + this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w; + this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w; + + return this; + + }, + + divideScalar: function ( scalar ) { + + return this.multiplyScalar( 1 / scalar ); + + }, + + setAxisAngleFromQuaternion: function ( q ) { + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm + + // q is assumed to be normalized + + this.w = 2 * Math.acos( q.w ); + + var s = Math.sqrt( 1 - q.w * q.w ); + + if ( s < 0.0001 ) { + + this.x = 1; + this.y = 0; + this.z = 0; + + } else { + + this.x = q.x / s; + this.y = q.y / s; + this.z = q.z / s; + + } + + return this; + + }, + + setAxisAngleFromRotationMatrix: function ( m ) { + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + var angle, x, y, z, // variables for result + epsilon = 0.01, // margin to allow for rounding errors + epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees + + te = m.elements, + + m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], + m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], + m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; + + if ( ( Math.abs( m12 - m21 ) < epsilon ) && + ( Math.abs( m13 - m31 ) < epsilon ) && + ( Math.abs( m23 - m32 ) < epsilon ) ) { + + // singularity found + // first check for identity matrix which must have +1 for all terms + // in leading diagonal and zero in other terms + + if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && + ( Math.abs( m13 + m31 ) < epsilon2 ) && + ( Math.abs( m23 + m32 ) < epsilon2 ) && + ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { + + // this singularity is identity matrix so angle = 0 + + this.set( 1, 0, 0, 0 ); + + return this; // zero angle, arbitrary axis + + } + + // otherwise this singularity is angle = 180 + + angle = Math.PI; + + var xx = ( m11 + 1 ) / 2; + var yy = ( m22 + 1 ) / 2; + var zz = ( m33 + 1 ) / 2; + var xy = ( m12 + m21 ) / 4; + var xz = ( m13 + m31 ) / 4; + var yz = ( m23 + m32 ) / 4; + + if ( ( xx > yy ) && ( xx > zz ) ) { + + // m11 is the largest diagonal term + + if ( xx < epsilon ) { + + x = 0; + y = 0.707106781; + z = 0.707106781; + + } else { + + x = Math.sqrt( xx ); + y = xy / x; + z = xz / x; + + } + + } else if ( yy > zz ) { + + // m22 is the largest diagonal term + + if ( yy < epsilon ) { + + x = 0.707106781; + y = 0; + z = 0.707106781; + + } else { + + y = Math.sqrt( yy ); + x = xy / y; + z = yz / y; + + } + + } else { + + // m33 is the largest diagonal term so base result on this + + if ( zz < epsilon ) { + + x = 0.707106781; + y = 0.707106781; + z = 0; + + } else { + + z = Math.sqrt( zz ); + x = xz / z; + y = yz / z; + + } + + } + + this.set( x, y, z, angle ); + + return this; // return 180 deg rotation + + } + + // as we have reached here there are no singularities so we can handle normally + + var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + + ( m13 - m31 ) * ( m13 - m31 ) + + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize + + if ( Math.abs( s ) < 0.001 ) s = 1; + + // prevent divide by zero, should not happen if matrix is orthogonal and should be + // caught by singularity test above, but I've left it in just in case + + this.x = ( m32 - m23 ) / s; + this.y = ( m13 - m31 ) / s; + this.z = ( m21 - m12 ) / s; + this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); + + return this; + + }, + + min: function ( v ) { + + this.x = Math.min( this.x, v.x ); + this.y = Math.min( this.y, v.y ); + this.z = Math.min( this.z, v.z ); + this.w = Math.min( this.w, v.w ); + + return this; + + }, + + max: function ( v ) { + + this.x = Math.max( this.x, v.x ); + this.y = Math.max( this.y, v.y ); + this.z = Math.max( this.z, v.z ); + this.w = Math.max( this.w, v.w ); + + return this; + + }, + + clamp: function ( min, max ) { + + // This function assumes min < max, if this assumption isn't true it will not operate correctly + + this.x = Math.max( min.x, Math.min( max.x, this.x ) ); + this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + this.z = Math.max( min.z, Math.min( max.z, this.z ) ); + this.w = Math.max( min.w, Math.min( max.w, this.w ) ); + + return this; + + }, + + clampScalar: function () { + + var min, max; + + return function clampScalar( minVal, maxVal ) { + + if ( min === undefined ) { + + min = new Vector4(); + max = new Vector4(); + + } + + min.set( minVal, minVal, minVal, minVal ); + max.set( maxVal, maxVal, maxVal, maxVal ); + + return this.clamp( min, max ); + + }; + + }(), + + floor: function () { + + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); + this.w = Math.floor( this.w ); + + return this; + + }, + + ceil: function () { + + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); + this.w = Math.ceil( this.w ); + + return this; + + }, + + round: function () { + + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); + this.w = Math.round( this.w ); + + return this; + + }, + + roundToZero: function () { + + this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); + this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); + this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); + this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w ); + + return this; + + }, + + negate: function () { + + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; + this.w = - this.w; + + return this; + + }, + + dot: function ( v ) { + + return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; + + }, + + lengthSq: function () { + + return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + + }, + + length: function () { + + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); + + }, + + lengthManhattan: function () { + + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); + + }, + + normalize: function () { + + return this.divideScalar( this.length() ); + + }, + + setLength: function ( length ) { + + return this.multiplyScalar( length / this.length() ); + + }, + + lerp: function ( v, alpha ) { + + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; + this.w += ( v.w - this.w ) * alpha; + + return this; + + }, + + lerpVectors: function ( v1, v2, alpha ) { + + return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); + + }, + + equals: function ( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); + + }, + + fromArray: function ( array, offset ) { + + if ( offset === undefined ) offset = 0; + + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; + this.w = array[ offset + 3 ]; + + return this; + + }, + + toArray: function ( array, offset ) { + + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; + + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; + array[ offset + 3 ] = this.w; + + return array; + + }, + + fromBufferAttribute: function ( attribute, index, offset ) { + + if ( offset !== undefined ) { + + console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' ); + + } + + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); + this.z = attribute.getZ( index ); + this.w = attribute.getW( index ); + + return this; + + } + +}; + +/** + * @author szimek / https://github.com/szimek/ + * @author alteredq / http://alteredqualia.com/ + * @author Marius Kintel / https://github.com/kintel + */ + +/* + In options, we can specify: + * Texture parameters for an auto-generated target texture + * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers +*/ +function WebGLRenderTarget( width, height, options ) { + + this.uuid = _Math.generateUUID(); + + this.width = width; + this.height = height; + + this.scissor = new Vector4( 0, 0, width, height ); + this.scissorTest = false; + + this.viewport = new Vector4( 0, 0, width, height ); + + options = options || {}; + + if ( options.minFilter === undefined ) options.minFilter = LinearFilter; + + this.texture = new Texture( undefined, undefined, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); + + this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; + this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; + this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null; + +} + +WebGLRenderTarget.prototype = { + + constructor: WebGLRenderTarget, + + isWebGLRenderTarget: true, + + setSize: function ( width, height ) { + + if ( this.width !== width || this.height !== height ) { + + this.width = width; + this.height = height; + + this.dispose(); + + } + + this.viewport.set( 0, 0, width, height ); + this.scissor.set( 0, 0, width, height ); + + }, + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + copy: function ( source ) { + + this.width = source.width; + this.height = source.height; + + this.viewport.copy( source.viewport ); + + this.texture = source.texture.clone(); + + this.depthBuffer = source.depthBuffer; + this.stencilBuffer = source.stencilBuffer; + this.depthTexture = source.depthTexture; + + return this; + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +}; + +Object.assign( WebGLRenderTarget.prototype, EventDispatcher.prototype ); + +/** + * @author alteredq / http://alteredqualia.com + */ + +function WebGLRenderTargetCube( width, height, options ) { + + WebGLRenderTarget.call( this, width, height, options ); + + this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5 + this.activeMipMapLevel = 0; + +} + +WebGLRenderTargetCube.prototype = Object.create( WebGLRenderTarget.prototype ); +WebGLRenderTargetCube.prototype.constructor = WebGLRenderTargetCube; + +WebGLRenderTargetCube.prototype.isWebGLRenderTargetCube = true; + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + * @author bhouston / http://clara.io + */ + +function Quaternion( x, y, z, w ) { + + this._x = x || 0; + this._y = y || 0; + this._z = z || 0; + this._w = ( w !== undefined ) ? w : 1; + +} + +Quaternion.prototype = { + + constructor: Quaternion, + + get x () { + + return this._x; + + }, + + set x ( value ) { + + this._x = value; + this.onChangeCallback(); + + }, + + get y () { + + return this._y; + + }, + + set y ( value ) { + + this._y = value; + this.onChangeCallback(); + + }, + + get z () { + + return this._z; + + }, + + set z ( value ) { + + this._z = value; + this.onChangeCallback(); + + }, + + get w () { + + return this._w; + + }, + + set w ( value ) { + + this._w = value; + this.onChangeCallback(); + + }, + + set: function ( x, y, z, w ) { + + this._x = x; + this._y = y; + this._z = z; + this._w = w; + + this.onChangeCallback(); + + return this; + + }, + + clone: function () { + + return new this.constructor( this._x, this._y, this._z, this._w ); + + }, + + copy: function ( quaternion ) { + + this._x = quaternion.x; + this._y = quaternion.y; + this._z = quaternion.z; + this._w = quaternion.w; + + this.onChangeCallback(); + + return this; + + }, + + setFromEuler: function ( euler, update ) { + + if ( (euler && euler.isEuler) === false ) { + + throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' ); + + } + + // http://www.mathworks.com/matlabcentral/fileexchange/ + // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ + // content/SpinCalc.m + + var c1 = Math.cos( euler._x / 2 ); + var c2 = Math.cos( euler._y / 2 ); + var c3 = Math.cos( euler._z / 2 ); + var s1 = Math.sin( euler._x / 2 ); + var s2 = Math.sin( euler._y / 2 ); + var s3 = Math.sin( euler._z / 2 ); + + var order = euler.order; + + if ( order === 'XYZ' ) { + + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; + + } else if ( order === 'YXZ' ) { + + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; + + } else if ( order === 'ZXY' ) { + + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; + + } else if ( order === 'ZYX' ) { + + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; + + } else if ( order === 'YZX' ) { + + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; + + } else if ( order === 'XZY' ) { + + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; + + } + + if ( update !== false ) this.onChangeCallback(); + + return this; + + }, + + setFromAxisAngle: function ( axis, angle ) { + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm + + // assumes axis is normalized + + var halfAngle = angle / 2, s = Math.sin( halfAngle ); + + this._x = axis.x * s; + this._y = axis.y * s; + this._z = axis.z * s; + this._w = Math.cos( halfAngle ); + + this.onChangeCallback(); + + return this; + + }, + + setFromRotationMatrix: function ( m ) { + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + var te = m.elements, + + m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], + m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], + m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], + + trace = m11 + m22 + m33, + s; + + if ( trace > 0 ) { + + s = 0.5 / Math.sqrt( trace + 1.0 ); + + this._w = 0.25 / s; + this._x = ( m32 - m23 ) * s; + this._y = ( m13 - m31 ) * s; + this._z = ( m21 - m12 ) * s; + + } else if ( m11 > m22 && m11 > m33 ) { + + s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); + + this._w = ( m32 - m23 ) / s; + this._x = 0.25 * s; + this._y = ( m12 + m21 ) / s; + this._z = ( m13 + m31 ) / s; + + } else if ( m22 > m33 ) { + + s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); + + this._w = ( m13 - m31 ) / s; + this._x = ( m12 + m21 ) / s; + this._y = 0.25 * s; + this._z = ( m23 + m32 ) / s; + + } else { + + s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); + + this._w = ( m21 - m12 ) / s; + this._x = ( m13 + m31 ) / s; + this._y = ( m23 + m32 ) / s; + this._z = 0.25 * s; + + } + + this.onChangeCallback(); + + return this; + + }, + + setFromUnitVectors: function () { + + // http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final + + // assumes direction vectors vFrom and vTo are normalized + + var v1, r; + + var EPS = 0.000001; + + return function setFromUnitVectors( vFrom, vTo ) { + + if ( v1 === undefined ) v1 = new Vector3(); + + r = vFrom.dot( vTo ) + 1; + + if ( r < EPS ) { + + r = 0; + + if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { + + v1.set( - vFrom.y, vFrom.x, 0 ); + + } else { + + v1.set( 0, - vFrom.z, vFrom.y ); + + } + + } else { + + v1.crossVectors( vFrom, vTo ); + + } + + this._x = v1.x; + this._y = v1.y; + this._z = v1.z; + this._w = r; + + return this.normalize(); + + }; + + }(), + + inverse: function () { + + return this.conjugate().normalize(); + + }, + + conjugate: function () { + + this._x *= - 1; + this._y *= - 1; + this._z *= - 1; + + this.onChangeCallback(); + + return this; + + }, + + dot: function ( v ) { + + return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; + + }, + + lengthSq: function () { + + return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; + + }, + + length: function () { + + return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); + + }, + + normalize: function () { + + var l = this.length(); + + if ( l === 0 ) { + + this._x = 0; + this._y = 0; + this._z = 0; + this._w = 1; + + } else { + + l = 1 / l; + + this._x = this._x * l; + this._y = this._y * l; + this._z = this._z * l; + this._w = this._w * l; + + } + + this.onChangeCallback(); + + return this; + + }, + + multiply: function ( q, p ) { + + if ( p !== undefined ) { + + console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); + return this.multiplyQuaternions( q, p ); + + } + + return this.multiplyQuaternions( this, q ); + + }, + + premultiply: function ( q ) { + + return this.multiplyQuaternions( q, this ); + + }, + + multiplyQuaternions: function ( a, b ) { + + // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm + + var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; + var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; + + this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; + this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; + this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; + this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; + + this.onChangeCallback(); + + return this; + + }, + + slerp: function ( qb, t ) { + + if ( t === 0 ) return this; + if ( t === 1 ) return this.copy( qb ); + + var x = this._x, y = this._y, z = this._z, w = this._w; + + // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ + + var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; + + if ( cosHalfTheta < 0 ) { + + this._w = - qb._w; + this._x = - qb._x; + this._y = - qb._y; + this._z = - qb._z; + + cosHalfTheta = - cosHalfTheta; + + } else { + + this.copy( qb ); + + } + + if ( cosHalfTheta >= 1.0 ) { + + this._w = w; + this._x = x; + this._y = y; + this._z = z; + + return this; + + } + + var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta ); + + if ( Math.abs( sinHalfTheta ) < 0.001 ) { + + this._w = 0.5 * ( w + this._w ); + this._x = 0.5 * ( x + this._x ); + this._y = 0.5 * ( y + this._y ); + this._z = 0.5 * ( z + this._z ); + + return this; + + } + + var halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); + var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, + ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; + + this._w = ( w * ratioA + this._w * ratioB ); + this._x = ( x * ratioA + this._x * ratioB ); + this._y = ( y * ratioA + this._y * ratioB ); + this._z = ( z * ratioA + this._z * ratioB ); + + this.onChangeCallback(); + + return this; + + }, + + equals: function ( quaternion ) { + + return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); + + }, + + fromArray: function ( array, offset ) { + + if ( offset === undefined ) offset = 0; + + this._x = array[ offset ]; + this._y = array[ offset + 1 ]; + this._z = array[ offset + 2 ]; + this._w = array[ offset + 3 ]; + + this.onChangeCallback(); + + return this; + + }, + + toArray: function ( array, offset ) { + + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; + + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._w; + + return array; + + }, + + onChange: function ( callback ) { + + this.onChangeCallback = callback; + + return this; + + }, + + onChangeCallback: function () {} + +}; + +Object.assign( Quaternion, { + + slerp: function( qa, qb, qm, t ) { + + return qm.copy( qa ).slerp( qb, t ); + + }, + + slerpFlat: function( + dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { + + // fuzz-free, array-based Quaternion SLERP operation + + var x0 = src0[ srcOffset0 + 0 ], + y0 = src0[ srcOffset0 + 1 ], + z0 = src0[ srcOffset0 + 2 ], + w0 = src0[ srcOffset0 + 3 ], + + x1 = src1[ srcOffset1 + 0 ], + y1 = src1[ srcOffset1 + 1 ], + z1 = src1[ srcOffset1 + 2 ], + w1 = src1[ srcOffset1 + 3 ]; + + if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { + + var s = 1 - t, + + cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, + + dir = ( cos >= 0 ? 1 : - 1 ), + sqrSin = 1 - cos * cos; + + // Skip the Slerp for tiny steps to avoid numeric problems: + if ( sqrSin > Number.EPSILON ) { + + var sin = Math.sqrt( sqrSin ), + len = Math.atan2( sin, cos * dir ); + + s = Math.sin( s * len ) / sin; + t = Math.sin( t * len ) / sin; + + } + + var tDir = t * dir; + + x0 = x0 * s + x1 * tDir; + y0 = y0 * s + y1 * tDir; + z0 = z0 * s + z1 * tDir; + w0 = w0 * s + w1 * tDir; + + // Normalize in case we just did a lerp: + if ( s === 1 - t ) { + + var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); + + x0 *= f; + y0 *= f; + z0 *= f; + w0 *= f; + + } + + } + + dst[ dstOffset ] = x0; + dst[ dstOffset + 1 ] = y0; + dst[ dstOffset + 2 ] = z0; + dst[ dstOffset + 3 ] = w0; + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + * @author *kile / http://kile.stravaganza.org/ + * @author philogb / http://blog.thejit.org/ + * @author mikael emtinger / http://gomo.se/ + * @author egraether / http://egraether.com/ + * @author WestLangley / http://github.com/WestLangley + */ + +function Vector3( x, y, z ) { + + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; + +} + +Vector3.prototype = { + + constructor: Vector3, + + isVector3: true, + + set: function ( x, y, z ) { + + this.x = x; + this.y = y; + this.z = z; + + return this; + + }, + + setScalar: function ( scalar ) { + + this.x = scalar; + this.y = scalar; + this.z = scalar; + + return this; + + }, + + setX: function ( x ) { + + this.x = x; + + return this; + + }, + + setY: function ( y ) { + + this.y = y; + + return this; + + }, + + setZ: function ( z ) { + + this.z = z; + + return this; + + }, + + setComponent: function ( index, value ) { + + switch ( index ) { + + case 0: this.x = value; break; + case 1: this.y = value; break; + case 2: this.z = value; break; + default: throw new Error( 'index is out of range: ' + index ); + + } + + return this; + + }, + + getComponent: function ( index ) { + + switch ( index ) { + + case 0: return this.x; + case 1: return this.y; + case 2: return this.z; + default: throw new Error( 'index is out of range: ' + index ); + + } + + }, + + clone: function () { + + return new this.constructor( this.x, this.y, this.z ); + + }, + + copy: function ( v ) { + + this.x = v.x; + this.y = v.y; + this.z = v.z; + + return this; + + }, + + add: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + return this.addVectors( v, w ); + + } + + this.x += v.x; + this.y += v.y; + this.z += v.z; + + return this; + + }, + + addScalar: function ( s ) { + + this.x += s; + this.y += s; + this.z += s; + + return this; + + }, + + addVectors: function ( a, b ) { + + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; + + return this; + + }, + + addScaledVector: function ( v, s ) { + + this.x += v.x * s; + this.y += v.y * s; + this.z += v.z * s; + + return this; + + }, + + sub: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + return this.subVectors( v, w ); + + } + + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + + return this; + + }, + + subScalar: function ( s ) { + + this.x -= s; + this.y -= s; + this.z -= s; + + return this; + + }, + + subVectors: function ( a, b ) { + + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; + + return this; + + }, + + multiply: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); + return this.multiplyVectors( v, w ); + + } + + this.x *= v.x; + this.y *= v.y; + this.z *= v.z; + + return this; + + }, + + multiplyScalar: function ( scalar ) { + + if ( isFinite( scalar ) ) { + + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + + } else { + + this.x = 0; + this.y = 0; + this.z = 0; + + } + + return this; + + }, + + multiplyVectors: function ( a, b ) { + + this.x = a.x * b.x; + this.y = a.y * b.y; + this.z = a.z * b.z; + + return this; + + }, + + applyEuler: function () { + + var quaternion; + + return function applyEuler( euler ) { + + if ( (euler && euler.isEuler) === false ) { + + console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' ); + + } + + if ( quaternion === undefined ) quaternion = new Quaternion(); + + return this.applyQuaternion( quaternion.setFromEuler( euler ) ); + + }; + + }(), + + applyAxisAngle: function () { + + var quaternion; + + return function applyAxisAngle( axis, angle ) { + + if ( quaternion === undefined ) quaternion = new Quaternion(); + + return this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) ); + + }; + + }(), + + applyMatrix3: function ( m ) { + + var x = this.x, y = this.y, z = this.z; + var e = m.elements; + + this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z; + this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z; + this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z; + + return this; + + }, + + applyMatrix4: function ( m ) { + + var x = this.x, y = this.y, z = this.z; + var e = m.elements; + + this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ]; + this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ]; + this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ]; + var w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ]; + + return this.divideScalar( w ); + + }, + + applyQuaternion: function ( q ) { + + var x = this.x, y = this.y, z = this.z; + var qx = q.x, qy = q.y, qz = q.z, qw = q.w; + + // calculate quat * vector + + var ix = qw * x + qy * z - qz * y; + var iy = qw * y + qz * x - qx * z; + var iz = qw * z + qx * y - qy * x; + var iw = - qx * x - qy * y - qz * z; + + // calculate result * inverse quat + + this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy; + this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz; + this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx; + + return this; + + }, + + project: function () { + + var matrix; + + return function project( camera ) { + + if ( matrix === undefined ) matrix = new Matrix4(); + + matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) ); + return this.applyMatrix4( matrix ); + + }; + + }(), + + unproject: function () { + + var matrix; + + return function unproject( camera ) { + + if ( matrix === undefined ) matrix = new Matrix4(); + + matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) ); + return this.applyMatrix4( matrix ); + + }; + + }(), + + transformDirection: function ( m ) { + + // input: THREE.Matrix4 affine matrix + // vector interpreted as a direction + + var x = this.x, y = this.y, z = this.z; + var e = m.elements; + + this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z; + this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z; + this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z; + + return this.normalize(); + + }, + + divide: function ( v ) { + + this.x /= v.x; + this.y /= v.y; + this.z /= v.z; + + return this; + + }, + + divideScalar: function ( scalar ) { + + return this.multiplyScalar( 1 / scalar ); + + }, + + min: function ( v ) { + + this.x = Math.min( this.x, v.x ); + this.y = Math.min( this.y, v.y ); + this.z = Math.min( this.z, v.z ); + + return this; + + }, + + max: function ( v ) { + + this.x = Math.max( this.x, v.x ); + this.y = Math.max( this.y, v.y ); + this.z = Math.max( this.z, v.z ); + + return this; + + }, + + clamp: function ( min, max ) { + + // This function assumes min < max, if this assumption isn't true it will not operate correctly + + this.x = Math.max( min.x, Math.min( max.x, this.x ) ); + this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + this.z = Math.max( min.z, Math.min( max.z, this.z ) ); + + return this; + + }, + + clampScalar: function () { + + var min, max; + + return function clampScalar( minVal, maxVal ) { + + if ( min === undefined ) { + + min = new Vector3(); + max = new Vector3(); + + } + + min.set( minVal, minVal, minVal ); + max.set( maxVal, maxVal, maxVal ); + + return this.clamp( min, max ); + + }; + + }(), + + clampLength: function ( min, max ) { + + var length = this.length(); + + return this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length ); + + }, + + floor: function () { + + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); + + return this; + + }, + + ceil: function () { + + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); + + return this; + + }, + + round: function () { + + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); + + return this; + + }, + + roundToZero: function () { + + this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); + this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); + this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); + + return this; + + }, + + negate: function () { + + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; + + return this; + + }, + + dot: function ( v ) { + + return this.x * v.x + this.y * v.y + this.z * v.z; + + }, + + lengthSq: function () { + + return this.x * this.x + this.y * this.y + this.z * this.z; + + }, + + length: function () { + + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); + + }, + + lengthManhattan: function () { + + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); + + }, + + normalize: function () { + + return this.divideScalar( this.length() ); + + }, + + setLength: function ( length ) { + + return this.multiplyScalar( length / this.length() ); + + }, + + lerp: function ( v, alpha ) { + + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; + + return this; + + }, + + lerpVectors: function ( v1, v2, alpha ) { + + return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); + + }, + + cross: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); + return this.crossVectors( v, w ); + + } + + var x = this.x, y = this.y, z = this.z; + + this.x = y * v.z - z * v.y; + this.y = z * v.x - x * v.z; + this.z = x * v.y - y * v.x; + + return this; + + }, + + crossVectors: function ( a, b ) { + + var ax = a.x, ay = a.y, az = a.z; + var bx = b.x, by = b.y, bz = b.z; + + this.x = ay * bz - az * by; + this.y = az * bx - ax * bz; + this.z = ax * by - ay * bx; + + return this; + + }, + + projectOnVector: function ( vector ) { + + var scalar = vector.dot( this ) / vector.lengthSq(); + + return this.copy( vector ).multiplyScalar( scalar ); + + }, + + projectOnPlane: function () { + + var v1; + + return function projectOnPlane( planeNormal ) { + + if ( v1 === undefined ) v1 = new Vector3(); + + v1.copy( this ).projectOnVector( planeNormal ); + + return this.sub( v1 ); + + }; + + }(), + + reflect: function () { + + // reflect incident vector off plane orthogonal to normal + // normal is assumed to have unit length + + var v1; + + return function reflect( normal ) { + + if ( v1 === undefined ) v1 = new Vector3(); + + return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); + + }; + + }(), + + angleTo: function ( v ) { + + var theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) ); + + // clamp, to handle numerical problems + + return Math.acos( _Math.clamp( theta, - 1, 1 ) ); + + }, + + distanceTo: function ( v ) { + + return Math.sqrt( this.distanceToSquared( v ) ); + + }, + + distanceToSquared: function ( v ) { + + var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; + + return dx * dx + dy * dy + dz * dz; + + }, + + distanceToManhattan: function ( v ) { + + return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); + + }, + + setFromSpherical: function( s ) { + + var sinPhiRadius = Math.sin( s.phi ) * s.radius; + + this.x = sinPhiRadius * Math.sin( s.theta ); + this.y = Math.cos( s.phi ) * s.radius; + this.z = sinPhiRadius * Math.cos( s.theta ); + + return this; + + }, + + setFromCylindrical: function( c ) { + + this.x = c.radius * Math.sin( c.theta ); + this.y = c.y; + this.z = c.radius * Math.cos( c.theta ); + + return this; + + }, + + setFromMatrixPosition: function ( m ) { + + return this.setFromMatrixColumn( m, 3 ); + + }, + + setFromMatrixScale: function ( m ) { + + var sx = this.setFromMatrixColumn( m, 0 ).length(); + var sy = this.setFromMatrixColumn( m, 1 ).length(); + var sz = this.setFromMatrixColumn( m, 2 ).length(); + + this.x = sx; + this.y = sy; + this.z = sz; + + return this; + + }, + + setFromMatrixColumn: function ( m, index ) { + + if ( typeof m === 'number' ) { + + console.warn( 'THREE.Vector3: setFromMatrixColumn now expects ( matrix, index ).' ); + var temp = m; + m = index; + index = temp; + + } + + return this.fromArray( m.elements, index * 4 ); + + }, + + equals: function ( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); + + }, + + fromArray: function ( array, offset ) { + + if ( offset === undefined ) offset = 0; + + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; + + return this; + + }, + + toArray: function ( array, offset ) { + + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; + + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; + + return array; + + }, + + fromBufferAttribute: function ( attribute, index, offset ) { + + if ( offset !== undefined ) { + + console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' ); + + } + + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); + this.z = attribute.getZ( index ); + + return this; + + } + +}; + +/** + * @author mrdoob / 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 mikael emtinger / http://gomo.se/ + * @author timknip / http://www.floorplanner.com/ + * @author bhouston / http://clara.io + * @author WestLangley / http://github.com/WestLangley + */ + +function Matrix4() { + + this.elements = new Float32Array( [ + + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + + ] ); + + if ( arguments.length > 0 ) { + + console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' ); + + } + +} + +Matrix4.prototype = { + + constructor: Matrix4, + + isMatrix4: true, + + set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { + + var te = this.elements; + + te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; + te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; + te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; + te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; + + return this; + + }, + + identity: function () { + + this.set( + + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + clone: function () { + + return new Matrix4().fromArray( this.elements ); + + }, + + copy: function ( m ) { + + this.elements.set( m.elements ); + + return this; + + }, + + copyPosition: function ( m ) { + + var te = this.elements; + var me = m.elements; + + te[ 12 ] = me[ 12 ]; + te[ 13 ] = me[ 13 ]; + te[ 14 ] = me[ 14 ]; + + return this; + + }, + + extractBasis: function ( xAxis, yAxis, zAxis ) { + + xAxis.setFromMatrixColumn( this, 0 ); + yAxis.setFromMatrixColumn( this, 1 ); + zAxis.setFromMatrixColumn( this, 2 ); + + return this; + + }, + + makeBasis: function ( xAxis, yAxis, zAxis ) { + + this.set( + xAxis.x, yAxis.x, zAxis.x, 0, + xAxis.y, yAxis.y, zAxis.y, 0, + xAxis.z, yAxis.z, zAxis.z, 0, + 0, 0, 0, 1 + ); + + return this; + + }, + + extractRotation: function () { + + var v1; + + return function extractRotation( m ) { + + if ( v1 === undefined ) v1 = new Vector3(); + + var te = this.elements; + var me = m.elements; + + var scaleX = 1 / v1.setFromMatrixColumn( m, 0 ).length(); + var scaleY = 1 / v1.setFromMatrixColumn( m, 1 ).length(); + var scaleZ = 1 / v1.setFromMatrixColumn( m, 2 ).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; + + }; + + }(), + + makeRotationFromEuler: function ( euler ) { + + if ( (euler && euler.isEuler) === false ) { + + console.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); + + } + + var te = this.elements; + + var x = euler.x, y = euler.y, z = euler.z; + var a = Math.cos( x ), b = Math.sin( x ); + var c = Math.cos( y ), d = Math.sin( y ); + var e = Math.cos( z ), f = Math.sin( z ); + + if ( euler.order === 'XYZ' ) { + + var 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; + + } else if ( euler.order === 'YXZ' ) { + + var 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; + + } else if ( euler.order === 'ZXY' ) { + + var 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; + + } else if ( euler.order === 'ZYX' ) { + + var 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; + + } else if ( euler.order === 'YZX' ) { + + var 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; + + } else if ( euler.order === 'XZY' ) { + + var 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; + + } + + // last column + te[ 3 ] = 0; + te[ 7 ] = 0; + te[ 11 ] = 0; + + // bottom row + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; + + return this; + + }, + + makeRotationFromQuaternion: function ( q ) { + + var te = this.elements; + + var x = q.x, y = q.y, z = q.z, w = q.w; + var x2 = x + x, y2 = y + y, z2 = z + z; + var xx = x * x2, xy = x * y2, xz = x * z2; + var yy = y * y2, yz = y * z2, zz = z * z2; + var wx = w * x2, wy = w * y2, wz = w * z2; + + te[ 0 ] = 1 - ( yy + zz ); + te[ 4 ] = xy - wz; + te[ 8 ] = xz + wy; + + te[ 1 ] = xy + wz; + te[ 5 ] = 1 - ( xx + zz ); + te[ 9 ] = yz - wx; + + te[ 2 ] = xz - wy; + te[ 6 ] = yz + wx; + te[ 10 ] = 1 - ( xx + yy ); + + // last column + te[ 3 ] = 0; + te[ 7 ] = 0; + te[ 11 ] = 0; + + // bottom row + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; + + return this; + + }, + + lookAt: function () { + + var x, y, z; + + return function lookAt( eye, target, up ) { + + if ( x === undefined ) { + + x = new Vector3(); + y = new Vector3(); + z = new Vector3(); + + } + + var te = this.elements; + + z.subVectors( eye, target ).normalize(); + + if ( z.lengthSq() === 0 ) { + + z.z = 1; + + } + + x.crossVectors( up, z ).normalize(); + + if ( x.lengthSq() === 0 ) { + + z.z += 0.0001; + x.crossVectors( up, z ).normalize(); + + } + + y.crossVectors( z, x ); + + + 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; + + }; + + }(), + + multiply: function ( m, n ) { + + if ( n !== undefined ) { + + console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); + return this.multiplyMatrices( m, n ); + + } + + return this.multiplyMatrices( this, m ); + + }, + + premultiply: function ( m ) { + + return this.multiplyMatrices( m, this ); + + }, + + multiplyMatrices: function ( a, b ) { + + var ae = a.elements; + var be = b.elements; + var te = this.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; + + }, + + multiplyToArray: function ( a, b, r ) { + + var te = this.elements; + + this.multiplyMatrices( 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; + + }, + + multiplyScalar: function ( s ) { + + var te = this.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; + + }, + + applyToBufferAttribute: function () { + + var v1; + + return function applyToBufferAttribute( attribute ) { + + if ( v1 === undefined ) v1 = new Vector3(); + + for ( var i = 0, l = attribute.count; i < l; i ++ ) { + + v1.x = attribute.getX( i ); + v1.y = attribute.getY( i ); + v1.z = attribute.getZ( i ); + + v1.applyMatrix4( this ); + + attribute.setXYZ( i, v1.x, v1.y, v1.z ); + + } + + return attribute; + + }; + + }(), + + determinant: function () { + + var te = this.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 ( + n41 * ( + + n14 * n23 * n32 + - n13 * n24 * n32 + - n14 * n22 * n33 + + n12 * n24 * n33 + + n13 * n22 * n34 + - n12 * n23 * n34 + ) + + n42 * ( + + n11 * n23 * n34 + - n11 * n24 * n33 + + n14 * n21 * n33 + - n13 * n21 * n34 + + n13 * n24 * n31 + - n14 * n23 * n31 + ) + + n43 * ( + + n11 * n24 * n32 + - n11 * n22 * n34 + - n14 * n21 * n32 + + n12 * n21 * n34 + + n14 * n22 * n31 + - n12 * n24 * n31 + ) + + n44 * ( + - n13 * n22 * n31 + - n11 * n23 * n32 + + n11 * n22 * n33 + + n13 * n21 * n32 + - n12 * n21 * n33 + + n12 * n23 * n31 + ) + + ); + + }, + + transpose: function () { + + var te = this.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; + + }, + + setPosition: function ( v ) { + + var te = this.elements; + + te[ 12 ] = v.x; + te[ 13 ] = v.y; + te[ 14 ] = v.z; + + return this; + + }, + + getInverse: function ( m, throwOnDegenerate ) { + + // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm + var te = this.elements, + me = m.elements, + + n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], n41 = me[ 3 ], + n12 = me[ 4 ], n22 = me[ 5 ], n32 = me[ 6 ], n42 = me[ 7 ], + n13 = me[ 8 ], n23 = me[ 9 ], n33 = me[ 10 ], n43 = me[ 11 ], + n14 = me[ 12 ], n24 = me[ 13 ], n34 = me[ 14 ], n44 = me[ 15 ], + + t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44, + t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44, + t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44, + t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; + + var det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; + + if ( det === 0 ) { + + var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0"; + + if ( throwOnDegenerate === true ) { + + throw new Error( msg ); + + } else { + + console.warn( msg ); + + } + + return this.identity(); + + } + + var detInv = 1 / det; + + te[ 0 ] = t11 * detInv; + te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; + te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; + te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; + + te[ 4 ] = t12 * detInv; + te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; + te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; + te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; + + te[ 8 ] = t13 * detInv; + te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; + te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; + te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; + + te[ 12 ] = t14 * detInv; + te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; + te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; + te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; + + return this; + + }, + + scale: function ( v ) { + + var te = this.elements; + var 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; + + }, + + getMaxScaleOnAxis: function () { + + var te = this.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, scaleYSq, scaleZSq ) ); + + }, + + makeTranslation: function ( x, y, z ) { + + this.set( + + 1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1 + + ); + + return this; + + }, + + makeRotationX: function ( theta ) { + + var c = Math.cos( theta ), s = Math.sin( theta ); + + this.set( + + 1, 0, 0, 0, + 0, c, - s, 0, + 0, s, c, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + makeRotationY: function ( theta ) { + + var c = Math.cos( theta ), s = Math.sin( theta ); + + this.set( + + c, 0, s, 0, + 0, 1, 0, 0, + - s, 0, c, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + makeRotationZ: function ( theta ) { + + var c = Math.cos( theta ), s = Math.sin( theta ); + + this.set( + + c, - s, 0, 0, + s, c, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + makeRotationAxis: function ( axis, angle ) { + + // Based on http://www.gamedev.net/reference/articles/article1199.asp + + var c = Math.cos( angle ); + var s = Math.sin( angle ); + var t = 1 - c; + var x = axis.x, y = axis.y, z = axis.z; + var tx = t * x, ty = t * y; + + this.set( + + tx * x + c, tx * y - s * z, tx * z + s * y, 0, + tx * y + s * z, ty * y + c, ty * z - s * x, 0, + tx * z - s * y, ty * z + s * x, t * z * z + c, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + makeScale: function ( x, y, z ) { + + this.set( + + x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + makeShear: function ( x, y, z ) { + + this.set( + + 1, y, z, 0, + x, 1, z, 0, + x, y, 1, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + compose: function ( position, quaternion, scale ) { + + this.makeRotationFromQuaternion( quaternion ); + this.scale( scale ); + this.setPosition( position ); + + return this; + + }, + + decompose: function () { + + var vector, matrix; + + return function decompose( position, quaternion, scale ) { + + if ( vector === undefined ) { + + vector = new Vector3(); + matrix = new Matrix4(); + + } + + var te = this.elements; + + var sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); + var sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); + var sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); + + // if determine is negative, we need to invert one scale + var det = this.determinant(); + if ( det < 0 ) { + + sx = - sx; + + } + + position.x = te[ 12 ]; + position.y = te[ 13 ]; + position.z = te[ 14 ]; + + // scale the rotation part + + matrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy() + + var invSX = 1 / sx; + var invSY = 1 / sy; + var invSZ = 1 / sz; + + matrix.elements[ 0 ] *= invSX; + matrix.elements[ 1 ] *= invSX; + matrix.elements[ 2 ] *= invSX; + + matrix.elements[ 4 ] *= invSY; + matrix.elements[ 5 ] *= invSY; + matrix.elements[ 6 ] *= invSY; + + matrix.elements[ 8 ] *= invSZ; + matrix.elements[ 9 ] *= invSZ; + matrix.elements[ 10 ] *= invSZ; + + quaternion.setFromRotationMatrix( matrix ); + + scale.x = sx; + scale.y = sy; + scale.z = sz; + + return this; + + }; + + }(), + + makePerspective: function ( left, right, top, bottom, near, far ) { + + if ( far === undefined ) { + + console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' ); + + } + + var te = this.elements; + var x = 2 * near / ( right - left ); + var y = 2 * near / ( top - bottom ); + + var a = ( right + left ) / ( right - left ); + var b = ( top + bottom ) / ( top - bottom ); + var c = - ( far + near ) / ( far - near ); + var d = - 2 * far * near / ( far - near ); + + te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; + te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; + te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; + te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; + + return this; + + }, + + makeOrthographic: function ( left, right, top, bottom, near, far ) { + + var te = this.elements; + var w = 1.0 / ( right - left ); + var h = 1.0 / ( top - bottom ); + var p = 1.0 / ( far - near ); + + var x = ( right + left ) * w; + var y = ( top + bottom ) * h; + var z = ( far + near ) * p; + + te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; + te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y; + te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z; + te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; + + return this; + + }, + + equals: function ( matrix ) { + + var te = this.elements; + var me = matrix.elements; + + for ( var i = 0; i < 16; i ++ ) { + + if ( te[ i ] !== me[ i ] ) return false; + + } + + return true; + + }, + + fromArray: function ( array, offset ) { + + if ( offset === undefined ) offset = 0; + + for( var i = 0; i < 16; i ++ ) { + + this.elements[ i ] = array[ i + offset ]; + + } + + return this; + + }, + + toArray: function ( array, offset ) { + + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; + + var te = this.elements; + + array[ offset ] = te[ 0 ]; + array[ offset + 1 ] = te[ 1 ]; + array[ offset + 2 ] = te[ 2 ]; + array[ offset + 3 ] = te[ 3 ]; + + array[ offset + 4 ] = te[ 4 ]; + array[ offset + 5 ] = te[ 5 ]; + array[ offset + 6 ] = te[ 6 ]; + array[ offset + 7 ] = te[ 7 ]; + + array[ offset + 8 ] = te[ 8 ]; + array[ offset + 9 ] = te[ 9 ]; + array[ offset + 10 ] = te[ 10 ]; + array[ offset + 11 ] = te[ 11 ]; + + array[ offset + 12 ] = te[ 12 ]; + array[ offset + 13 ] = te[ 13 ]; + array[ offset + 14 ] = te[ 14 ]; + array[ offset + 15 ] = te[ 15 ]; + + return array; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { + + images = images !== undefined ? images : []; + mapping = mapping !== undefined ? mapping : CubeReflectionMapping; + + Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); + + this.flipY = false; + +} + +CubeTexture.prototype = Object.create( Texture.prototype ); +CubeTexture.prototype.constructor = CubeTexture; + +CubeTexture.prototype.isCubeTexture = true; + +Object.defineProperty( CubeTexture.prototype, 'images', { + + get: function () { + + return this.image; + + }, + + set: function ( value ) { + + this.image = value; + + } + +} ); + +/** + * @author tschw + * + * Uniforms of a program. + * Those form a tree structure with a special top-level container for the root, + * which you get by calling 'new WebGLUniforms( gl, program, renderer )'. + * + * + * Properties of inner nodes including the top-level container: + * + * .seq - array of nested uniforms + * .map - nested uniforms by name + * + * + * Methods of all nodes except the top-level container: + * + * .setValue( gl, value, [renderer] ) + * + * uploads a uniform value(s) + * the 'renderer' parameter is needed for sampler uniforms + * + * + * Static methods of the top-level container (renderer factorizations): + * + * .upload( gl, seq, values, renderer ) + * + * sets uniforms in 'seq' to 'values[id].value' + * + * .seqWithValue( seq, values ) : filteredSeq + * + * filters 'seq' entries with corresponding entry in values + * + * + * Methods of the top-level container (renderer factorizations): + * + * .setValue( gl, name, value ) + * + * sets uniform with name 'name' to 'value' + * + * .set( gl, obj, prop ) + * + * sets uniform from object and property with same name than uniform + * + * .setOptional( gl, obj, prop ) + * + * like .set for an optional property of the object + * + */ + +var emptyTexture = new Texture(); +var emptyCubeTexture = new CubeTexture(); + +// --- Base for inner nodes (including the root) --- + +function UniformContainer() { + + this.seq = []; + this.map = {}; + +} + +// --- Utilities --- + +// Array Caches (provide typed arrays for temporary by size) + +var arrayCacheF32 = []; +var arrayCacheI32 = []; + +// Flattening for arrays of vectors and matrices + +function flatten( array, nBlocks, blockSize ) { + + var firstElem = array[ 0 ]; + + if ( firstElem <= 0 || firstElem > 0 ) return array; + // unoptimized: ! isNaN( firstElem ) + // see http://jacksondunstan.com/articles/983 + + var n = nBlocks * blockSize, + r = arrayCacheF32[ n ]; + + if ( r === undefined ) { + + r = new Float32Array( n ); + arrayCacheF32[ n ] = r; + + } + + if ( nBlocks !== 0 ) { + + firstElem.toArray( r, 0 ); + + for ( var i = 1, offset = 0; i !== nBlocks; ++ i ) { + + offset += blockSize; + array[ i ].toArray( r, offset ); + + } + + } + + return r; + +} + +// Texture unit allocation + +function allocTexUnits( renderer, n ) { + + var r = arrayCacheI32[ n ]; + + if ( r === undefined ) { + + r = new Int32Array( n ); + arrayCacheI32[ n ] = r; + + } + + for ( var i = 0; i !== n; ++ i ) + r[ i ] = renderer.allocTextureUnit(); + + return r; + +} + +// --- Setters --- + +// Note: Defining these methods externally, because they come in a bunch +// and this way their names minify. + +// Single scalar + +function setValue1f( gl, v ) { gl.uniform1f( this.addr, v ); } +function setValue1i( gl, v ) { gl.uniform1i( this.addr, v ); } + +// Single float vector (from flat array or THREE.VectorN) + +function setValue2fv( gl, v ) { + + if ( v.x === undefined ) gl.uniform2fv( this.addr, v ); + else gl.uniform2f( this.addr, v.x, v.y ); + +} + +function setValue3fv( gl, v ) { + + if ( v.x !== undefined ) + gl.uniform3f( this.addr, v.x, v.y, v.z ); + else if ( v.r !== undefined ) + gl.uniform3f( this.addr, v.r, v.g, v.b ); + else + gl.uniform3fv( this.addr, v ); + +} + +function setValue4fv( gl, v ) { + + if ( v.x === undefined ) gl.uniform4fv( this.addr, v ); + else gl.uniform4f( this.addr, v.x, v.y, v.z, v.w ); + +} + +// Single matrix (from flat array or MatrixN) + +function setValue2fm( gl, v ) { + + gl.uniformMatrix2fv( this.addr, false, v.elements || v ); + +} + +function setValue3fm( gl, v ) { + + gl.uniformMatrix3fv( this.addr, false, v.elements || v ); + +} + +function setValue4fm( gl, v ) { + + gl.uniformMatrix4fv( this.addr, false, v.elements || v ); + +} + +// Single texture (2D / Cube) + +function setValueT1( gl, v, renderer ) { + + var unit = renderer.allocTextureUnit(); + gl.uniform1i( this.addr, unit ); + renderer.setTexture2D( v || emptyTexture, unit ); + +} + +function setValueT6( gl, v, renderer ) { + + var unit = renderer.allocTextureUnit(); + gl.uniform1i( this.addr, unit ); + renderer.setTextureCube( v || emptyCubeTexture, unit ); + +} + +// Integer / Boolean vectors or arrays thereof (always flat arrays) + +function setValue2iv( gl, v ) { gl.uniform2iv( this.addr, v ); } +function setValue3iv( gl, v ) { gl.uniform3iv( this.addr, v ); } +function setValue4iv( gl, v ) { gl.uniform4iv( this.addr, v ); } + +// Helper to pick the right setter for the singular case + +function getSingularSetter( type ) { + + switch ( type ) { + + case 0x1406: return setValue1f; // FLOAT + case 0x8b50: return setValue2fv; // _VEC2 + case 0x8b51: return setValue3fv; // _VEC3 + case 0x8b52: return setValue4fv; // _VEC4 + + case 0x8b5a: return setValue2fm; // _MAT2 + case 0x8b5b: return setValue3fm; // _MAT3 + case 0x8b5c: return setValue4fm; // _MAT4 + + case 0x8b5e: return setValueT1; // SAMPLER_2D + case 0x8b60: return setValueT6; // SAMPLER_CUBE + + case 0x1404: case 0x8b56: return setValue1i; // INT, BOOL + case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2 + case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3 + case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4 + + } + +} + +// Array of scalars + +function setValue1fv( gl, v ) { gl.uniform1fv( this.addr, v ); } +function setValue1iv( gl, v ) { gl.uniform1iv( this.addr, v ); } + +// Array of vectors (flat or from THREE classes) + +function setValueV2a( gl, v ) { + + gl.uniform2fv( this.addr, flatten( v, this.size, 2 ) ); + +} + +function setValueV3a( gl, v ) { + + gl.uniform3fv( this.addr, flatten( v, this.size, 3 ) ); + +} + +function setValueV4a( gl, v ) { + + gl.uniform4fv( this.addr, flatten( v, this.size, 4 ) ); + +} + +// Array of matrices (flat or from THREE clases) + +function setValueM2a( gl, v ) { + + gl.uniformMatrix2fv( this.addr, false, flatten( v, this.size, 4 ) ); + +} + +function setValueM3a( gl, v ) { + + gl.uniformMatrix3fv( this.addr, false, flatten( v, this.size, 9 ) ); + +} + +function setValueM4a( gl, v ) { + + gl.uniformMatrix4fv( this.addr, false, flatten( v, this.size, 16 ) ); + +} + +// Array of textures (2D / Cube) + +function setValueT1a( gl, v, renderer ) { + + var n = v.length, + units = allocTexUnits( renderer, n ); + + gl.uniform1iv( this.addr, units ); + + for ( var i = 0; i !== n; ++ i ) { + + renderer.setTexture2D( v[ i ] || emptyTexture, units[ i ] ); + + } + +} + +function setValueT6a( gl, v, renderer ) { + + var n = v.length, + units = allocTexUnits( renderer, n ); + + gl.uniform1iv( this.addr, units ); + + for ( var i = 0; i !== n; ++ i ) { + + renderer.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] ); + + } + +} + +// Helper to pick the right setter for a pure (bottom-level) array + +function getPureArraySetter( type ) { + + switch ( type ) { + + case 0x1406: return setValue1fv; // FLOAT + case 0x8b50: return setValueV2a; // _VEC2 + case 0x8b51: return setValueV3a; // _VEC3 + case 0x8b52: return setValueV4a; // _VEC4 + + case 0x8b5a: return setValueM2a; // _MAT2 + case 0x8b5b: return setValueM3a; // _MAT3 + case 0x8b5c: return setValueM4a; // _MAT4 + + case 0x8b5e: return setValueT1a; // SAMPLER_2D + case 0x8b60: return setValueT6a; // SAMPLER_CUBE + + case 0x1404: case 0x8b56: return setValue1iv; // INT, BOOL + case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2 + case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3 + case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4 + + } + +} + +// --- Uniform Classes --- + +function SingleUniform( id, activeInfo, addr ) { + + this.id = id; + this.addr = addr; + this.setValue = getSingularSetter( activeInfo.type ); + + // this.path = activeInfo.name; // DEBUG + +} + +function PureArrayUniform( id, activeInfo, addr ) { + + this.id = id; + this.addr = addr; + this.size = activeInfo.size; + this.setValue = getPureArraySetter( activeInfo.type ); + + // this.path = activeInfo.name; // DEBUG + +} + +function StructuredUniform( id ) { + + this.id = id; + + UniformContainer.call( this ); // mix-in + +} + +StructuredUniform.prototype.setValue = function( gl, value ) { + + // Note: Don't need an extra 'renderer' parameter, since samplers + // are not allowed in structured uniforms. + + var seq = this.seq; + + for ( var i = 0, n = seq.length; i !== n; ++ i ) { + + var u = seq[ i ]; + u.setValue( gl, value[ u.id ] ); + + } + +}; + +// --- Top-level --- + +// Parser - builds up the property tree from the path strings + +var RePathPart = /([\w\d_]+)(\])?(\[|\.)?/g; + +// extracts +// - the identifier (member name or array index) +// - followed by an optional right bracket (found when array index) +// - followed by an optional left bracket or dot (type of subscript) +// +// Note: These portions can be read in a non-overlapping fashion and +// allow straightforward parsing of the hierarchy that WebGL encodes +// in the uniform names. + +function addUniform( container, uniformObject ) { + + container.seq.push( uniformObject ); + container.map[ uniformObject.id ] = uniformObject; + +} + +function parseUniform( activeInfo, addr, container ) { + + var path = activeInfo.name, + pathLength = path.length; + + // reset RegExp object, because of the early exit of a previous run + RePathPart.lastIndex = 0; + + for (; ;) { + + var match = RePathPart.exec( path ), + matchEnd = RePathPart.lastIndex, + + id = match[ 1 ], + idIsIndex = match[ 2 ] === ']', + subscript = match[ 3 ]; + + if ( idIsIndex ) id = id | 0; // convert to integer + + if ( subscript === undefined || + subscript === '[' && matchEnd + 2 === pathLength ) { + // bare name or "pure" bottom-level array "[0]" suffix + + addUniform( container, subscript === undefined ? + new SingleUniform( id, activeInfo, addr ) : + new PureArrayUniform( id, activeInfo, addr ) ); + + break; + + } else { + // step into inner node / create it in case it doesn't exist + + var map = container.map, + next = map[ id ]; + + if ( next === undefined ) { + + next = new StructuredUniform( id ); + addUniform( container, next ); + + } + + container = next; + + } + + } + +} + +// Root Container + +function WebGLUniforms( gl, program, renderer ) { + + UniformContainer.call( this ); + + this.renderer = renderer; + + var n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS ); + + for ( var i = 0; i < n; ++ i ) { + + var info = gl.getActiveUniform( program, i ), + path = info.name, + addr = gl.getUniformLocation( program, path ); + + parseUniform( info, addr, this ); + + } + +} + +WebGLUniforms.prototype.setValue = function( gl, name, value ) { + + var u = this.map[ name ]; + + if ( u !== undefined ) u.setValue( gl, value, this.renderer ); + +}; + +WebGLUniforms.prototype.set = function( gl, object, name ) { + + var u = this.map[ name ]; + + if ( u !== undefined ) u.setValue( gl, object[ name ], this.renderer ); + +}; + +WebGLUniforms.prototype.setOptional = function( gl, object, name ) { + + var v = object[ name ]; + + if ( v !== undefined ) this.setValue( gl, name, v ); + +}; + + +// Static interface + +WebGLUniforms.upload = function( gl, seq, values, renderer ) { + + for ( var i = 0, n = seq.length; i !== n; ++ i ) { + + var u = seq[ i ], + v = values[ u.id ]; + + if ( v.needsUpdate !== false ) { + // note: always updating when .needsUpdate is undefined + + u.setValue( gl, v.value, renderer ); + + } + + } + +}; + +WebGLUniforms.seqWithValue = function( seq, values ) { + + var r = []; + + for ( var i = 0, n = seq.length; i !== n; ++ i ) { + + var u = seq[ i ]; + if ( u.id in values ) r.push( u ); + + } + + return r; + +}; + +/** + * Uniform Utilities + */ + +var UniformsUtils = { + + merge: function ( uniforms ) { + + var merged = {}; + + for ( var u = 0; u < uniforms.length; u ++ ) { + + var tmp = this.clone( uniforms[ u ] ); + + for ( var p in tmp ) { + + merged[ p ] = tmp[ p ]; + + } + + } + + return merged; + + }, + + clone: function ( uniforms_src ) { + + var uniforms_dst = {}; + + for ( var u in uniforms_src ) { + + uniforms_dst[ u ] = {}; + + for ( var p in uniforms_src[ u ] ) { + + var parameter_src = uniforms_src[ u ][ p ]; + + if ( parameter_src && ( parameter_src.isColor || + parameter_src.isMatrix3 || parameter_src.isMatrix4 || + parameter_src.isVector2 || parameter_src.isVector3 || parameter_src.isVector4 || + parameter_src.isTexture ) ) { + + uniforms_dst[ u ][ p ] = parameter_src.clone(); + + } else if ( Array.isArray( parameter_src ) ) { + + uniforms_dst[ u ][ p ] = parameter_src.slice(); + + } else { + + uniforms_dst[ u ][ p ] = parameter_src; + + } + + } + + } + + return uniforms_dst; + + } + +}; + +var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif\n"; + +var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif\n"; + +var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif\n"; + +var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\n\t#endif\n#endif\n"; + +var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; + +var begin_vertex = "\nvec3 transformed = vec3( position );\n"; + +var beginnormal_vertex = "\nvec3 objectNormal = vec3( normal );\n"; + +var bsdfs = "float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t\tif( decayExponent > 0.0 ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\t\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t\treturn distanceFalloff * maxDistanceCutoffFactor;\n#else\n\t\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n#endif\n\t\t}\n\t\treturn 1.0;\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 ltcTextureCoords( const in GeometricContext geometry, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = (LUT_SIZE - 1.0)/LUT_SIZE;\n\tconst float LUT_BIAS = 0.5/LUT_SIZE;\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 P = geometry.position;\n\tfloat theta = acos( dot( N, V ) );\n\tvec2 uv = vec2(\n\t\tsqrt( saturate( roughness ) ),\n\t\tsaturate( theta / ( 0.5 * PI ) ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nvoid clipQuadToHorizon( inout vec3 L[5], out int n ) {\n\tint config = 0;\n\tif ( L[0].z > 0.0 ) config += 1;\n\tif ( L[1].z > 0.0 ) config += 2;\n\tif ( L[2].z > 0.0 ) config += 4;\n\tif ( L[3].z > 0.0 ) config += 8;\n\tn = 0;\n\tif ( config == 0 ) {\n\t} else if ( config == 1 ) {\n\t\tn = 3;\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t\tL[2] = -L[3].z * L[0] + L[0].z * L[3];\n\t} else if ( config == 2 ) {\n\t\tn = 3;\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t} else if ( config == 3 ) {\n\t\tn = 4;\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t\tL[3] = -L[3].z * L[0] + L[0].z * L[3];\n\t} else if ( config == 4 ) {\n\t\tn = 3;\n\t\tL[0] = -L[3].z * L[2] + L[2].z * L[3];\n\t\tL[1] = -L[1].z * L[2] + L[2].z * L[1];\n\t} else if ( config == 5 ) {\n\t\tn = 0;\n\t} else if ( config == 6 ) {\n\t\tn = 4;\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t\tL[3] = -L[3].z * L[2] + L[2].z * L[3];\n\t} else if ( config == 7 ) {\n\t\tn = 5;\n\t\tL[4] = -L[3].z * L[0] + L[0].z * L[3];\n\t\tL[3] = -L[3].z * L[2] + L[2].z * L[3];\n\t} else if ( config == 8 ) {\n\t\tn = 3;\n\t\tL[0] = -L[0].z * L[3] + L[3].z * L[0];\n\t\tL[1] = -L[2].z * L[3] + L[3].z * L[2];\n\t\tL[2] = L[3];\n\t} else if ( config == 9 ) {\n\t\tn = 4;\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t\tL[2] = -L[2].z * L[3] + L[3].z * L[2];\n\t} else if ( config == 10 ) {\n\t\tn = 0;\n\t} else if ( config == 11 ) {\n\t\tn = 5;\n\t\tL[4] = L[3];\n\t\tL[3] = -L[2].z * L[3] + L[3].z * L[2];\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t} else if ( config == 12 ) {\n\t\tn = 4;\n\t\tL[1] = -L[1].z * L[2] + L[2].z * L[1];\n\t\tL[0] = -L[0].z * L[3] + L[3].z * L[0];\n\t} else if ( config == 13 ) {\n\t\tn = 5;\n\t\tL[4] = L[3];\n\t\tL[3] = L[2];\n\t\tL[2] = -L[1].z * L[2] + L[2].z * L[1];\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t} else if ( config == 14 ) {\n\t\tn = 5;\n\t\tL[4] = -L[0].z * L[3] + L[3].z * L[0];\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t} else if ( config == 15 ) {\n\t\tn = 4;\n\t}\n\tif ( n == 3 )\n\t\tL[3] = L[0];\n\tif ( n == 4 )\n\t\tL[4] = L[0];\n}\nfloat integrateLtcBrdfOverRectEdge( vec3 v1, vec3 v2 ) {\n\tfloat cosTheta = dot( v1, v2 );\n\tfloat theta = acos( cosTheta );\n\tfloat res = cross( v1, v2 ).z * ( ( theta > 0.001 ) ? theta / sin( theta ) : 1.0 );\n\treturn res;\n}\nvoid initRectPoints( const in vec3 pos, const in vec3 halfWidth, const in vec3 halfHeight, out vec3 rectPoints[4] ) {\n\trectPoints[0] = pos - halfWidth - halfHeight;\n\trectPoints[1] = pos + halfWidth - halfHeight;\n\trectPoints[2] = pos + halfWidth + halfHeight;\n\trectPoints[3] = pos - halfWidth + halfHeight;\n}\nvec3 integrateLtcBrdfOverRect( const in GeometricContext geometry, const in mat3 brdfMat, const in vec3 rectPoints[4] ) {\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 P = geometry.position;\n\tvec3 T1, T2;\n\tT1 = normalize(V - N * dot( V, N ));\n\tT2 = - cross( N, T1 );\n\tmat3 brdfWrtSurface = brdfMat * transpose( mat3( T1, T2, N ) );\n\tvec3 clippedRect[5];\n\tclippedRect[0] = brdfWrtSurface * ( rectPoints[0] - P );\n\tclippedRect[1] = brdfWrtSurface * ( rectPoints[1] - P );\n\tclippedRect[2] = brdfWrtSurface * ( rectPoints[2] - P );\n\tclippedRect[3] = brdfWrtSurface * ( rectPoints[3] - P );\n\tint n;\n\tclipQuadToHorizon(clippedRect, n);\n\tif ( n == 0 )\n\t\treturn vec3( 0, 0, 0 );\n\tclippedRect[0] = normalize( clippedRect[0] );\n\tclippedRect[1] = normalize( clippedRect[1] );\n\tclippedRect[2] = normalize( clippedRect[2] );\n\tclippedRect[3] = normalize( clippedRect[3] );\n\tclippedRect[4] = normalize( clippedRect[4] );\n\tfloat sum = 0.0;\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[0], clippedRect[1] );\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[1], clippedRect[2] );\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[2], clippedRect[3] );\n\tif (n >= 4)\n\t\tsum += integrateLtcBrdfOverRectEdge( clippedRect[3], clippedRect[4] );\n\tif (n == 5)\n\t\tsum += integrateLtcBrdfOverRectEdge( clippedRect[4], clippedRect[0] );\n\tsum = max( 0.0, sum );\n\tvec3 Lo_i = vec3( sum, sum, sum );\n\treturn Lo_i;\n}\nvec3 Rect_Area_Light_Specular_Reflectance(\n\t\tconst in GeometricContext geometry,\n\t\tconst in vec3 lightPos, const in vec3 lightHalfWidth, const in vec3 lightHalfHeight,\n\t\tconst in float roughness,\n\t\tconst in sampler2D ltcMat, const in sampler2D ltcMag ) {\n\tvec3 rectPoints[4];\n\tinitRectPoints( lightPos, lightHalfWidth, lightHalfHeight, rectPoints );\n\tvec2 uv = ltcTextureCoords( geometry, roughness );\n\tvec4 brdfLtcApproxParams, t;\n\tbrdfLtcApproxParams = texture2D( ltcMat, uv );\n\tt = texture2D( ltcMat, uv );\n\tfloat brdfLtcScalar = texture2D( ltcMag, uv ).a;\n\tmat3 brdfLtcApproxMat = mat3(\n\t\tvec3( 1, 0, t.y ),\n\t\tvec3( 0, t.z, 0 ),\n\t\tvec3( t.w, 0, t.x )\n\t);\n\tvec3 specularReflectance = integrateLtcBrdfOverRect( geometry, brdfLtcApproxMat, rectPoints );\n\tspecularReflectance *= brdfLtcScalar;\n\treturn specularReflectance;\n}\nvec3 Rect_Area_Light_Diffuse_Reflectance(\n\t\tconst in GeometricContext geometry,\n\t\tconst in vec3 lightPos, const in vec3 lightHalfWidth, const in vec3 lightHalfHeight ) {\n\tvec3 rectPoints[4];\n\tinitRectPoints( lightPos, lightHalfWidth, lightHalfHeight, rectPoints );\n\tmat3 diffuseBrdfMat = mat3(1);\n\tvec3 diffuseReflectance = integrateLtcBrdfOverRect( geometry, diffuseBrdfMat, rectPoints );\n\treturn diffuseReflectance;\n}\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n\treturn specularColor * AB.x + AB.y;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n"; + +var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = dFdx( surf_pos );\n\t\tvec3 vSigmaY = dFdy( surf_pos );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif\n"; + +var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; ++ i ) {\n\t\tvec4 plane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t\t\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; ++ i ) {\n\t\t\tvec4 plane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t\n\t#endif\n#endif\n"; + +var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif\n"; + +var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvarying vec3 vViewPosition;\n#endif\n"; + +var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n"; + +var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif"; + +var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif\n"; + +var color_pars_vertex = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif"; + +var color_vertex = "#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif"; + +var common = "#define PI 3.14159265359\n#define PI2 6.28318530718\n#define PI_HALF 1.5707963267949\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 transpose( const in mat3 v ) {\n\tmat3 tmp;\n\ttmp[0] = vec3(v[0].x, v[1].x, v[2].x);\n\ttmp[1] = vec3(v[0].y, v[1].y, v[2].y);\n\ttmp[2] = vec3(v[0].z, v[1].z, v[2].z);\n\treturn tmp;\n}\n"; + +var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_textureSize (1024.0)\nint getFaceFromDirection(vec3 direction) {\n\tvec3 absDirection = abs(direction);\n\tint face = -1;\n\tif( absDirection.x > absDirection.z ) {\n\t\tif(absDirection.x > absDirection.y )\n\t\t\tface = direction.x > 0.0 ? 0 : 3;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\telse {\n\t\tif(absDirection.z > absDirection.y )\n\t\t\tface = direction.z > 0.0 ? 2 : 5;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\treturn face;\n}\n#define cubeUV_maxLods1 (log2(cubeUV_textureSize*0.25) - 1.0)\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\n\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\n\tfloat dxRoughness = dFdx(roughness);\n\tfloat dyRoughness = dFdy(roughness);\n\tvec3 dx = dFdx( vec * scale * dxRoughness );\n\tvec3 dy = dFdy( vec * scale * dyRoughness );\n\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\n\td = clamp(d, 1.0, cubeUV_rangeClamp);\n\tfloat mipLevel = 0.5 * log2(d);\n\treturn vec2(floor(mipLevel), fract(mipLevel));\n}\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\n\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\n\tfloat a = 16.0 * cubeUV_rcpTextureSize;\n\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\n\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\n\tfloat powScale = exp2_packed.x * exp2_packed.y;\n\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\n\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\n\tbool bRes = mipLevel == 0.0;\n\tscale = bRes && (scale < a) ? a : scale;\n\tvec3 r;\n\tvec2 offset;\n\tint face = getFaceFromDirection(direction);\n\tfloat rcpPowScale = 1.0 / powScale;\n\tif( face == 0) {\n\t\tr = vec3(direction.x, -direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 1) {\n\t\tr = vec3(direction.y, direction.x, direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 2) {\n\t\tr = vec3(direction.z, direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 3) {\n\t\tr = vec3(direction.x, direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse if( face == 4) {\n\t\tr = vec3(direction.y, direction.x, -direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse {\n\t\tr = vec3(direction.z, -direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\tr = normalize(r);\n\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\n\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\n\tvec2 base = offset + vec2( texelOffset );\n\treturn base + s * ( scale - 2.0 * texelOffset );\n}\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\nvec4 textureCubeUV(vec3 reflectedDirection, float roughness ) {\n\tfloat roughnessVal = roughness* cubeUV_maxLods3;\n\tfloat r1 = floor(roughnessVal);\n\tfloat r2 = r1 + 1.0;\n\tfloat t = fract(roughnessVal);\n\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\n\tfloat s = mipInfo.y;\n\tfloat level0 = mipInfo.x;\n\tfloat level1 = level0 + 1.0;\n\tlevel1 = level1 > 5.0 ? 5.0 : level1;\n\tlevel0 += min( floor( s + 0.5 ), 5.0 );\n\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\n\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\n\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\n\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\n\tvec4 result = mix(color10, color20, t);\n\treturn vec4(result.rgb, 1.0);\n}\n#endif\n"; + +var defaultnormal_vertex = "#ifdef FLIP_SIDED\n\tobjectNormal = -objectNormal;\n#endif\nvec3 transformedNormal = normalMatrix * objectNormal;\n"; + +var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif\n"; + +var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normal * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif\n"; + +var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif\n"; + +var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif\n"; + +var encodings_fragment = " gl_FragColor = linearToOutputTexel( gl_FragColor );\n"; + +var encodings_pars_fragment = "\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.xyz * value.w * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = min( floor( D ) / 255.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = value.rgb * cLogLuvM;\n\tXp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract(Le);\n\tvResult.z = (Le - (floor(vResult.w*255.0))/255.0)/255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;\n\treturn vec4( max(vRGB, 0.0), 1.0 );\n}\n"; + +var envmap_fragment = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\tsampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\n\t\tsampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\tvec3 reflectView = flipNormal * normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\tenvColor = envMapTexelToLinear( envColor );\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif\n"; + +var envmap_pars_fragment = "#if defined( USE_ENVMAP ) || defined( PHYSICAL )\n\tuniform float reflectivity;\n\tuniform float envMapIntensity;\n#endif\n#ifdef USE_ENVMAP\n\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\n\t\tvarying vec3 vWorldPosition;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif\n"; + +var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif\n"; + +var envmap_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif\n"; + +var fog_vertex = "\n#ifdef USE_FOG\nfogDepth = -mvPosition.z;\n#endif"; + +var fog_pars_vertex = "#ifdef USE_FOG\n varying float fogDepth;\n#endif\n"; + +var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif\n"; + +var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif\n"; + +var gradientmap_pars_fragment = "#ifdef TOON\n\tuniform sampler2D gradientMap;\n\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\t\tfloat dotNL = dot( normal, lightDirection );\n\t\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t\t#ifdef USE_GRADIENTMAP\n\t\t\treturn texture2D( gradientMap, coord ).rgb;\n\t\t#else\n\t\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t\t#endif\n\t}\n#endif\n"; + +var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif\n"; + +var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; + +var lights_lambert_vertex = "vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\n#if NUM_POINT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_DIR_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif\n"; + +var lights_pars = "uniform vec3 ambientLightColor;\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltcMat;\tuniform sampler2D ltcMag;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif\n#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\tvec4 envMapColor = textureCubeUV( queryVec, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\tvec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent));\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV;\n\t\t\tsampleUV.y = saturate( reflectVec.y * 0.5 + 0.5 );\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif\n"; + +var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;\n"; + +var lights_phong_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_BlinnPhong( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 matDiffColor = material.diffuseColor;\n\t\tvec3 matSpecColor = material.specularColor;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = BlinnExponentToGGXRoughness( material.specularShininess );\n\t\tvec3 spec = Rect_Area_Light_Specular_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight,\n\t\t\t\troughness,\n\t\t\t\tltcMat, ltcMag );\n\t\tvec3 diff = Rect_Area_Light_Diffuse_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight );\n\t\treflectedLight.directSpecular += lightColor * matSpecColor * spec / PI2;\n\t\treflectedLight.directDiffuse += lightColor * matDiffColor * diff / PI2;\n\t}\n#endif\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifdef TOON\n\t\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#else\n\t\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\t\tvec3 irradiance = dotNL * directLight.color;\n\t#endif\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)\n"; + +var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\n#ifdef STANDARD\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.clearCoat = saturate( clearCoat );\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\n#endif\n"; + +var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n\t#ifndef STANDARD\n\t\tfloat clearCoat;\n\t\tfloat clearCoatRoughness;\n\t#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearCoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 matDiffColor = material.diffuseColor;\n\t\tvec3 matSpecColor = material.specularColor;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.specularRoughness;\n\t\tvec3 spec = Rect_Area_Light_Specular_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight,\n\t\t\t\troughness,\n\t\t\t\tltcMat, ltcMag );\n\t\tvec3 diff = Rect_Area_Light_Diffuse_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight );\n\t\treflectedLight.directSpecular += lightColor * matSpecColor * spec;\n\t\treflectedLight.directDiffuse += lightColor * matDiffColor * diff;\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifndef STANDARD\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\n\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\t#ifndef STANDARD\n\t\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifndef STANDARD\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\tfloat dotNL = dotNV;\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\n\t#ifndef STANDARD\n\t\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\n#define Material_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.specularRoughness )\n#define Material_ClearCoat_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}\n"; + +var lights_template = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = normalize( vViewPosition );\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#ifdef USE_LIGHTMAP\n\t\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tirradiance += getLightProbeIndirectIrradiance( geometry, 8 );\n\t#endif\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tvec3 radiance = getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), 8 );\n\t#ifndef STANDARD\n\t\tvec3 clearCoatRadiance = getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), 8 );\n\t#else\n\t\tvec3 clearCoatRadiance = vec3( 0.0 );\n\t#endif\n\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\n#endif\n"; + +var logdepthbuf_fragment = "#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n#endif"; + +var logdepthbuf_pars_fragment = "#ifdef USE_LOGDEPTHBUF\n\tuniform float logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n#endif\n"; + +var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n\tuniform float logDepthBufFC;\n#endif"; + +var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\tgl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t#else\n\t\tgl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\n\t#endif\n#endif\n"; + +var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif\n"; + +var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n"; + +var map_particle_fragment = "#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n"; + +var map_particle_pars_fragment = "#ifdef USE_MAP\n\tuniform vec4 offsetRepeat;\n\tuniform sampler2D map;\n#endif\n"; + +var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.r;\n#endif\n"; + +var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; + +var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n#endif\n"; + +var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\t#ifndef USE_MORPHNORMALS\n\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif"; + +var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\t#endif\n#endif\n"; + +var normal_flip = "#ifdef DOUBLE_SIDED\n\tfloat flipNormal = ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n#else\n\tfloat flipNormal = 1.0;\n#endif\n"; + +var normal_fragment = "#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal ) * flipNormal;\n#endif\n#ifdef USE_NORMALMAP\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n"; + +var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n\t\tvec3 N = normalize( surf_norm );\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy = normalScale * mapN.xy;\n\t\tmat3 tsn = mat3( S, T, N );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif\n"; + +var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 1.0 - 2.0 * rgb.xyz;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}\n"; + +var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif\n"; + +var project_vertex = "#ifdef USE_SKINNING\n\tvec4 mvPosition = modelViewMatrix * skinned;\n#else\n\tvec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\n#endif\ngl_Position = projectionMatrix * mvPosition;\n"; + +var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.r;\n#endif\n"; + +var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; + +var shadowmap_pars_fragment = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\n\t\tconst vec2 offset = vec2( 0.0, 1.0 );\n\t\tvec2 texelSize = vec2( 1.0 ) / size;\n\t\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\n\t\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\n\t\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\n\t\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\n\t\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\n\t\tvec2 f = fract( uv * size + 0.5 );\n\t\tfloat a = mix( lb, lt, f.y );\n\t\tfloat b = mix( rb, rt, f.y );\n\t\tfloat c = mix( a, b, f.x );\n\t\treturn c;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\treturn (\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn 1.0;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\tfloat dp = ( length( lightToPosition ) - shadowBias ) / 1000.0;\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif\n"; + +var shadowmap_pars_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n#endif\n"; + +var shadowmap_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n#endif\n"; + +var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#endif\n\treturn shadow;\n}\n"; + +var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif"; + +var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform sampler2D boneTexture;\n\t\tuniform int boneTextureWidth;\n\t\tuniform int boneTextureHeight;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureWidth ) );\n\t\t\tfloat y = floor( j / float( boneTextureWidth ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureWidth );\n\t\t\tfloat dy = 1.0 / float( boneTextureHeight );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif\n"; + +var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\tskinned = bindMatrixInverse * skinned;\n#endif\n"; + +var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n#endif\n"; + +var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif"; + +var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; + +var tonemapping_fragment = "#if defined( TONE_MAPPING )\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif\n"; + +var tonemapping_pars_fragment = "#define saturate(a) clamp( a, 0.0, 1.0 )\nuniform float toneMappingExposure;\nuniform float toneMappingWhitePoint;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\nvec3 Uncharted2ToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\n"; + +var uv_pars_fragment = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n#endif"; + +var uv_pars_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n\tuniform vec4 offsetRepeat;\n#endif\n"; + +var uv_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n#endif"; + +var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif"; + +var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n#endif"; + +var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif"; + +var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( PHYSICAL ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\n\t#ifdef USE_SKINNING\n\t\tvec4 worldPosition = modelMatrix * skinned;\n\t#else\n\t\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n\t#endif\n#endif\n"; + +var cube_frag = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldPosition;\n#include \nvoid main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n\tgl_FragColor.a *= opacity;\n}\n"; + +var cube_vert = "varying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}\n"; + +var depth_frag = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( gl_FragCoord.z ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n\t#endif\n}\n"; + +var depth_vert = "#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + +var distanceRGBA_frag = "uniform vec3 lightPos;\nvarying vec4 vWorldPosition;\n#include \n#include \n#include \nvoid main () {\n\t#include \n\tgl_FragColor = packDepthToRGBA( length( vWorldPosition.xyz - lightPos.xyz ) / 1000.0 );\n}\n"; + +var distanceRGBA_vert = "varying vec4 vWorldPosition;\n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition;\n}\n"; + +var equirect_frag = "uniform sampler2D tEquirect;\nuniform float tFlip;\nvarying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldPosition );\n\tvec2 sampleUV;\n\tsampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n}\n"; + +var equirect_vert = "varying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}\n"; + +var linedashed_frag = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + +var linedashed_vert = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}\n"; + +var meshbasic_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + +var meshbasic_vert = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifdef USE_ENVMAP\n\t#include \n\t#include \n\t#include \n\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + +var meshlambert_frag = "uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n\t#include \n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + +var meshlambert_vert = "#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + +var meshphong_frag = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + +var meshphong_vert = "#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + +var meshphysical_frag = "#define PHYSICAL\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifndef STANDARD\n\tuniform float clearCoat;\n\tuniform float clearCoatRoughness;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + +var meshphysical_vert = "#define PHYSICAL\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}\n"; + +var normal_frag = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}\n"; + +var normal_vert = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}\n"; + +var points_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + +var points_vert = "uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_SIZEATTENUATION\n\t\tgl_PointSize = size * ( scale / - mvPosition.z );\n\t#else\n\t\tgl_PointSize = size;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + +var shadow_frag = "uniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tgl_FragColor = vec4( 0.0, 0.0, 0.0, opacity * ( 1.0 - getShadowMask() ) );\n}\n"; + +var shadow_vert = "#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + +var ShaderChunk = { + alphamap_fragment: alphamap_fragment, + alphamap_pars_fragment: alphamap_pars_fragment, + alphatest_fragment: alphatest_fragment, + aomap_fragment: aomap_fragment, + aomap_pars_fragment: aomap_pars_fragment, + begin_vertex: begin_vertex, + beginnormal_vertex: beginnormal_vertex, + bsdfs: bsdfs, + bumpmap_pars_fragment: bumpmap_pars_fragment, + clipping_planes_fragment: clipping_planes_fragment, + clipping_planes_pars_fragment: clipping_planes_pars_fragment, + clipping_planes_pars_vertex: clipping_planes_pars_vertex, + clipping_planes_vertex: clipping_planes_vertex, + color_fragment: color_fragment, + color_pars_fragment: color_pars_fragment, + color_pars_vertex: color_pars_vertex, + color_vertex: color_vertex, + common: common, + cube_uv_reflection_fragment: cube_uv_reflection_fragment, + defaultnormal_vertex: defaultnormal_vertex, + displacementmap_pars_vertex: displacementmap_pars_vertex, + displacementmap_vertex: displacementmap_vertex, + emissivemap_fragment: emissivemap_fragment, + emissivemap_pars_fragment: emissivemap_pars_fragment, + encodings_fragment: encodings_fragment, + encodings_pars_fragment: encodings_pars_fragment, + envmap_fragment: envmap_fragment, + envmap_pars_fragment: envmap_pars_fragment, + envmap_pars_vertex: envmap_pars_vertex, + envmap_vertex: envmap_vertex, + fog_vertex: fog_vertex, + fog_pars_vertex: fog_pars_vertex, + fog_fragment: fog_fragment, + fog_pars_fragment: fog_pars_fragment, + gradientmap_pars_fragment: gradientmap_pars_fragment, + lightmap_fragment: lightmap_fragment, + lightmap_pars_fragment: lightmap_pars_fragment, + lights_lambert_vertex: lights_lambert_vertex, + lights_pars: lights_pars, + lights_phong_fragment: lights_phong_fragment, + lights_phong_pars_fragment: lights_phong_pars_fragment, + lights_physical_fragment: lights_physical_fragment, + lights_physical_pars_fragment: lights_physical_pars_fragment, + lights_template: lights_template, + logdepthbuf_fragment: logdepthbuf_fragment, + logdepthbuf_pars_fragment: logdepthbuf_pars_fragment, + logdepthbuf_pars_vertex: logdepthbuf_pars_vertex, + logdepthbuf_vertex: logdepthbuf_vertex, + map_fragment: map_fragment, + map_pars_fragment: map_pars_fragment, + map_particle_fragment: map_particle_fragment, + map_particle_pars_fragment: map_particle_pars_fragment, + metalnessmap_fragment: metalnessmap_fragment, + metalnessmap_pars_fragment: metalnessmap_pars_fragment, + morphnormal_vertex: morphnormal_vertex, + morphtarget_pars_vertex: morphtarget_pars_vertex, + morphtarget_vertex: morphtarget_vertex, + normal_flip: normal_flip, + normal_fragment: normal_fragment, + normalmap_pars_fragment: normalmap_pars_fragment, + packing: packing, + premultiplied_alpha_fragment: premultiplied_alpha_fragment, + project_vertex: project_vertex, + roughnessmap_fragment: roughnessmap_fragment, + roughnessmap_pars_fragment: roughnessmap_pars_fragment, + shadowmap_pars_fragment: shadowmap_pars_fragment, + shadowmap_pars_vertex: shadowmap_pars_vertex, + shadowmap_vertex: shadowmap_vertex, + shadowmask_pars_fragment: shadowmask_pars_fragment, + skinbase_vertex: skinbase_vertex, + skinning_pars_vertex: skinning_pars_vertex, + skinning_vertex: skinning_vertex, + skinnormal_vertex: skinnormal_vertex, + specularmap_fragment: specularmap_fragment, + specularmap_pars_fragment: specularmap_pars_fragment, + tonemapping_fragment: tonemapping_fragment, + tonemapping_pars_fragment: tonemapping_pars_fragment, + uv_pars_fragment: uv_pars_fragment, + uv_pars_vertex: uv_pars_vertex, + uv_vertex: uv_vertex, + uv2_pars_fragment: uv2_pars_fragment, + uv2_pars_vertex: uv2_pars_vertex, + uv2_vertex: uv2_vertex, + worldpos_vertex: worldpos_vertex, + + cube_frag: cube_frag, + cube_vert: cube_vert, + depth_frag: depth_frag, + depth_vert: depth_vert, + distanceRGBA_frag: distanceRGBA_frag, + distanceRGBA_vert: distanceRGBA_vert, + equirect_frag: equirect_frag, + equirect_vert: equirect_vert, + linedashed_frag: linedashed_frag, + linedashed_vert: linedashed_vert, + meshbasic_frag: meshbasic_frag, + meshbasic_vert: meshbasic_vert, + meshlambert_frag: meshlambert_frag, + meshlambert_vert: meshlambert_vert, + meshphong_frag: meshphong_frag, + meshphong_vert: meshphong_vert, + meshphysical_frag: meshphysical_frag, + meshphysical_vert: meshphysical_vert, + normal_frag: normal_frag, + normal_vert: normal_vert, + points_frag: points_frag, + points_vert: points_vert, + shadow_frag: shadow_frag, + shadow_vert: shadow_vert +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function Color( r, g, b ) { + + if ( g === undefined && b === undefined ) { + + // r is THREE.Color, hex or string + return this.set( r ); + + } + + return this.setRGB( r, g, b ); + +} + +Color.prototype = { + + constructor: Color, + + isColor: true, + + r: 1, g: 1, b: 1, + + set: function ( value ) { + + if ( value && value.isColor ) { + + this.copy( value ); + + } else if ( typeof value === 'number' ) { + + this.setHex( value ); + + } else if ( typeof value === 'string' ) { + + this.setStyle( value ); + + } + + return this; + + }, + + setScalar: function ( scalar ) { + + this.r = scalar; + this.g = scalar; + this.b = scalar; + + return this; + + }, + + setHex: function ( hex ) { + + hex = Math.floor( hex ); + + this.r = ( hex >> 16 & 255 ) / 255; + this.g = ( hex >> 8 & 255 ) / 255; + this.b = ( hex & 255 ) / 255; + + return this; + + }, + + setRGB: function ( r, g, b ) { + + this.r = r; + this.g = g; + this.b = b; + + return this; + + }, + + setHSL: function () { + + function hue2rgb( p, q, t ) { + + if ( t < 0 ) t += 1; + if ( t > 1 ) t -= 1; + if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; + if ( t < 1 / 2 ) return q; + if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); + return p; + + } + + return function setHSL( h, s, l ) { + + // h,s,l ranges are in 0.0 - 1.0 + h = _Math.euclideanModulo( h, 1 ); + s = _Math.clamp( s, 0, 1 ); + l = _Math.clamp( l, 0, 1 ); + + if ( s === 0 ) { + + this.r = this.g = this.b = l; + + } else { + + var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); + var q = ( 2 * l ) - p; + + this.r = hue2rgb( q, p, h + 1 / 3 ); + this.g = hue2rgb( q, p, h ); + this.b = hue2rgb( q, p, h - 1 / 3 ); + + } + + return this; + + }; + + }(), + + setStyle: function ( style ) { + + function handleAlpha( string ) { + + if ( string === undefined ) return; + + if ( parseFloat( string ) < 1 ) { + + console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); + + } + + } + + + var m; + + if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) { + + // rgb / hsl + + var color; + var name = m[ 1 ]; + var components = m[ 2 ]; + + switch ( name ) { + + case 'rgb': + case 'rgba': + + if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { + + // rgb(255,0,0) rgba(255,0,0,0.5) + this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255; + this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255; + this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255; + + handleAlpha( color[ 5 ] ); + + return this; + + } + + if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { + + // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) + this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100; + this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100; + this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100; + + handleAlpha( color[ 5 ] ); + + return this; + + } + + break; + + case 'hsl': + case 'hsla': + + if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { + + // hsl(120,50%,50%) hsla(120,50%,50%,0.5) + var h = parseFloat( color[ 1 ] ) / 360; + var s = parseInt( color[ 2 ], 10 ) / 100; + var l = parseInt( color[ 3 ], 10 ) / 100; + + handleAlpha( color[ 5 ] ); + + return this.setHSL( h, s, l ); + + } + + break; + + } + + } else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) { + + // hex color + + var hex = m[ 1 ]; + var size = hex.length; + + if ( size === 3 ) { + + // #ff0 + this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255; + this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255; + this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255; + + return this; + + } else if ( size === 6 ) { + + // #ff0000 + this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255; + this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255; + this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255; + + return this; + + } + + } + + if ( style && style.length > 0 ) { + + // color keywords + var hex = ColorKeywords[ style ]; + + if ( hex !== undefined ) { + + // red + this.setHex( hex ); + + } else { + + // unknown color + console.warn( 'THREE.Color: Unknown color ' + style ); + + } + + } + + return this; + + }, + + clone: function () { + + return new this.constructor( this.r, this.g, this.b ); + + }, + + copy: function ( color ) { + + this.r = color.r; + this.g = color.g; + this.b = color.b; + + return this; + + }, + + copyGammaToLinear: function ( color, gammaFactor ) { + + if ( gammaFactor === undefined ) gammaFactor = 2.0; + + this.r = Math.pow( color.r, gammaFactor ); + this.g = Math.pow( color.g, gammaFactor ); + this.b = Math.pow( color.b, gammaFactor ); + + return this; + + }, + + copyLinearToGamma: function ( color, gammaFactor ) { + + if ( gammaFactor === undefined ) gammaFactor = 2.0; + + var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0; + + this.r = Math.pow( color.r, safeInverse ); + this.g = Math.pow( color.g, safeInverse ); + this.b = Math.pow( color.b, safeInverse ); + + return this; + + }, + + convertGammaToLinear: function () { + + var r = this.r, g = this.g, b = this.b; + + this.r = r * r; + this.g = g * g; + this.b = b * b; + + return this; + + }, + + convertLinearToGamma: function () { + + this.r = Math.sqrt( this.r ); + this.g = Math.sqrt( this.g ); + this.b = Math.sqrt( this.b ); + + return this; + + }, + + getHex: function () { + + return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0; + + }, + + getHexString: function () { + + return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 ); + + }, + + getHSL: function ( optionalTarget ) { + + // h,s,l ranges are in 0.0 - 1.0 + + var hsl = optionalTarget || { h: 0, s: 0, l: 0 }; + + var r = this.r, g = this.g, b = this.b; + + var max = Math.max( r, g, b ); + var min = Math.min( r, g, b ); + + var hue, saturation; + var lightness = ( min + max ) / 2.0; + + if ( min === max ) { + + hue = 0; + saturation = 0; + + } else { + + var delta = max - min; + + saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); + + switch ( max ) { + + case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; + case g: hue = ( b - r ) / delta + 2; break; + case b: hue = ( r - g ) / delta + 4; break; + + } + + hue /= 6; + + } + + hsl.h = hue; + hsl.s = saturation; + hsl.l = lightness; + + return hsl; + + }, + + getStyle: function () { + + return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')'; + + }, + + offsetHSL: function ( h, s, l ) { + + var hsl = this.getHSL(); + + hsl.h += h; hsl.s += s; hsl.l += l; + + this.setHSL( hsl.h, hsl.s, hsl.l ); + + return this; + + }, + + add: function ( color ) { + + this.r += color.r; + this.g += color.g; + this.b += color.b; + + return this; + + }, + + addColors: function ( color1, color2 ) { + + this.r = color1.r + color2.r; + this.g = color1.g + color2.g; + this.b = color1.b + color2.b; + + return this; + + }, + + addScalar: function ( s ) { + + this.r += s; + this.g += s; + this.b += s; + + return this; + + }, + + sub: function( color ) { + + this.r = Math.max( 0, this.r - color.r ); + this.g = Math.max( 0, this.g - color.g ); + this.b = Math.max( 0, this.b - color.b ); + + return this; + + }, + + multiply: function ( color ) { + + this.r *= color.r; + this.g *= color.g; + this.b *= color.b; + + return this; + + }, + + multiplyScalar: function ( s ) { + + this.r *= s; + this.g *= s; + this.b *= s; + + return this; + + }, + + lerp: function ( color, alpha ) { + + this.r += ( color.r - this.r ) * alpha; + this.g += ( color.g - this.g ) * alpha; + this.b += ( color.b - this.b ) * alpha; + + return this; + + }, + + equals: function ( c ) { + + return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); + + }, + + fromArray: function ( array, offset ) { + + if ( offset === undefined ) offset = 0; + + this.r = array[ offset ]; + this.g = array[ offset + 1 ]; + this.b = array[ offset + 2 ]; + + return this; + + }, + + toArray: function ( array, offset ) { + + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; + + array[ offset ] = this.r; + array[ offset + 1 ] = this.g; + array[ offset + 2 ] = this.b; + + return array; + + }, + + toJSON: function () { + + return this.getHex(); + + } + +}; + +var ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, +'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, +'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, +'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, +'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, +'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, +'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, +'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, +'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, +'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, +'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, +'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, +'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, +'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, +'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, +'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, +'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, +'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, +'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, +'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, +'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, +'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, +'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, +'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +function DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) { + + Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); + + this.image = { data: data, width: width, height: height }; + + this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; + this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; + + this.generateMipmaps = false; + this.flipY = false; + this.unpackAlignment = 1; + +} + +DataTexture.prototype = Object.create( Texture.prototype ); +DataTexture.prototype.constructor = DataTexture; + +DataTexture.prototype.isDataTexture = true; + +/** + * Uniforms library for shared webgl shaders + */ + +var UniformsLib = { + + common: { + + diffuse: { value: new Color( 0xeeeeee ) }, + opacity: { value: 1.0 }, + + map: { value: null }, + offsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) }, + + specularMap: { value: null }, + alphaMap: { value: null }, + + envMap: { value: null }, + flipEnvMap: { value: - 1 }, + reflectivity: { value: 1.0 }, + refractionRatio: { value: 0.98 } + + }, + + aomap: { + + aoMap: { value: null }, + aoMapIntensity: { value: 1 } + + }, + + lightmap: { + + lightMap: { value: null }, + lightMapIntensity: { value: 1 } + + }, + + emissivemap: { + + emissiveMap: { value: null } + + }, + + bumpmap: { + + bumpMap: { value: null }, + bumpScale: { value: 1 } + + }, + + normalmap: { + + normalMap: { value: null }, + normalScale: { value: new Vector2( 1, 1 ) } + + }, + + displacementmap: { + + displacementMap: { value: null }, + displacementScale: { value: 1 }, + displacementBias: { value: 0 } + + }, + + roughnessmap: { + + roughnessMap: { value: null } + + }, + + metalnessmap: { + + metalnessMap: { value: null } + + }, + + gradientmap: { + + gradientMap: { value: null } + + }, + + fog: { + + fogDensity: { value: 0.00025 }, + fogNear: { value: 1 }, + fogFar: { value: 2000 }, + fogColor: { value: new Color( 0xffffff ) } + + }, + + lights: { + + ambientLightColor: { value: [] }, + + directionalLights: { value: [], properties: { + direction: {}, + color: {}, + + shadow: {}, + shadowBias: {}, + shadowRadius: {}, + shadowMapSize: {} + } }, + + directionalShadowMap: { value: [] }, + directionalShadowMatrix: { value: [] }, + + spotLights: { value: [], properties: { + color: {}, + position: {}, + direction: {}, + distance: {}, + coneCos: {}, + penumbraCos: {}, + decay: {}, + + shadow: {}, + shadowBias: {}, + shadowRadius: {}, + shadowMapSize: {} + } }, + + spotShadowMap: { value: [] }, + spotShadowMatrix: { value: [] }, + + pointLights: { value: [], properties: { + color: {}, + position: {}, + decay: {}, + distance: {}, + + shadow: {}, + shadowBias: {}, + shadowRadius: {}, + shadowMapSize: {} + } }, + + pointShadowMap: { value: [] }, + pointShadowMatrix: { value: [] }, + + hemisphereLights: { value: [], properties: { + direction: {}, + skyColor: {}, + groundColor: {} + } }, + + // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src + rectAreaLights: { value: [], properties: { + color: {}, + position: {}, + width: {}, + height: {} + } } + + }, + + points: { + + diffuse: { value: new Color( 0xeeeeee ) }, + opacity: { value: 1.0 }, + size: { value: 1.0 }, + scale: { value: 1.0 }, + map: { value: null }, + offsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) } + + } + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + */ + +var ShaderLib = { + + basic: { + + uniforms: UniformsUtils.merge( [ + UniformsLib.common, + UniformsLib.aomap, + UniformsLib.lightmap, + UniformsLib.fog + ] ), + + vertexShader: ShaderChunk.meshbasic_vert, + fragmentShader: ShaderChunk.meshbasic_frag + + }, + + lambert: { + + uniforms: UniformsUtils.merge( [ + UniformsLib.common, + UniformsLib.aomap, + UniformsLib.lightmap, + UniformsLib.emissivemap, + UniformsLib.fog, + UniformsLib.lights, + { + emissive: { value: new Color( 0x000000 ) } + } + ] ), + + vertexShader: ShaderChunk.meshlambert_vert, + fragmentShader: ShaderChunk.meshlambert_frag + + }, + + phong: { + + uniforms: UniformsUtils.merge( [ + UniformsLib.common, + UniformsLib.aomap, + UniformsLib.lightmap, + UniformsLib.emissivemap, + UniformsLib.bumpmap, + UniformsLib.normalmap, + UniformsLib.displacementmap, + UniformsLib.gradientmap, + UniformsLib.fog, + UniformsLib.lights, + { + emissive: { value: new Color( 0x000000 ) }, + specular: { value: new Color( 0x111111 ) }, + shininess: { value: 30 } + } + ] ), + + vertexShader: ShaderChunk.meshphong_vert, + fragmentShader: ShaderChunk.meshphong_frag + + }, + + standard: { + + uniforms: UniformsUtils.merge( [ + UniformsLib.common, + UniformsLib.aomap, + UniformsLib.lightmap, + UniformsLib.emissivemap, + UniformsLib.bumpmap, + UniformsLib.normalmap, + UniformsLib.displacementmap, + UniformsLib.roughnessmap, + UniformsLib.metalnessmap, + UniformsLib.fog, + UniformsLib.lights, + { + emissive: { value: new Color( 0x000000 ) }, + roughness: { value: 0.5 }, + metalness: { value: 0 }, + envMapIntensity: { value: 1 } // temporary + } + ] ), + + vertexShader: ShaderChunk.meshphysical_vert, + fragmentShader: ShaderChunk.meshphysical_frag + + }, + + points: { + + uniforms: UniformsUtils.merge( [ + UniformsLib.points, + UniformsLib.fog + ] ), + + vertexShader: ShaderChunk.points_vert, + fragmentShader: ShaderChunk.points_frag + + }, + + dashed: { + + uniforms: UniformsUtils.merge( [ + UniformsLib.common, + UniformsLib.fog, + { + scale: { value: 1 }, + dashSize: { value: 1 }, + totalSize: { value: 2 } + } + ] ), + + vertexShader: ShaderChunk.linedashed_vert, + fragmentShader: ShaderChunk.linedashed_frag + + }, + + depth: { + + uniforms: UniformsUtils.merge( [ + UniformsLib.common, + UniformsLib.displacementmap + ] ), + + vertexShader: ShaderChunk.depth_vert, + fragmentShader: ShaderChunk.depth_frag + + }, + + normal: { + + uniforms: UniformsUtils.merge( [ + UniformsLib.common, + UniformsLib.bumpmap, + UniformsLib.normalmap, + UniformsLib.displacementmap, + { + opacity: { value: 1.0 } + } + ] ), + + vertexShader: ShaderChunk.normal_vert, + fragmentShader: ShaderChunk.normal_frag + + }, + + /* ------------------------------------------------------------------------- + // Cube map shader + ------------------------------------------------------------------------- */ + + cube: { + + uniforms: { + tCube: { value: null }, + tFlip: { value: - 1 }, + opacity: { value: 1.0 } + }, + + vertexShader: ShaderChunk.cube_vert, + fragmentShader: ShaderChunk.cube_frag + + }, + + /* ------------------------------------------------------------------------- + // Cube map shader + ------------------------------------------------------------------------- */ + + equirect: { + + uniforms: { + tEquirect: { value: null }, + tFlip: { value: - 1 } + }, + + vertexShader: ShaderChunk.equirect_vert, + fragmentShader: ShaderChunk.equirect_frag + + }, + + distanceRGBA: { + + uniforms: { + lightPos: { value: new Vector3() } + }, + + vertexShader: ShaderChunk.distanceRGBA_vert, + fragmentShader: ShaderChunk.distanceRGBA_frag + + } + +}; + +ShaderLib.physical = { + + uniforms: UniformsUtils.merge( [ + ShaderLib.standard.uniforms, + { + clearCoat: { value: 0 }, + clearCoatRoughness: { value: 0 } + } + ] ), + + vertexShader: ShaderChunk.meshphysical_vert, + fragmentShader: ShaderChunk.meshphysical_frag + +}; + +/** + * @author bhouston / http://clara.io + */ + +function Box2( min, max ) { + + this.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity ); + this.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity ); + +} + +Box2.prototype = { + + constructor: Box2, + + set: function ( min, max ) { + + this.min.copy( min ); + this.max.copy( max ); + + return this; + + }, + + setFromPoints: function ( points ) { + + this.makeEmpty(); + + for ( var i = 0, il = points.length; i < il; i ++ ) { + + this.expandByPoint( points[ i ] ); + + } + + return this; + + }, + + setFromCenterAndSize: function () { + + var v1 = new Vector2(); + + return function setFromCenterAndSize( center, size ) { + + var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); + + return this; + + }; + + }(), + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + copy: function ( box ) { + + this.min.copy( box.min ); + this.max.copy( box.max ); + + return this; + + }, + + makeEmpty: function () { + + this.min.x = this.min.y = + Infinity; + this.max.x = this.max.y = - Infinity; + + return this; + + }, + + isEmpty: function () { + + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); + + }, + + getCenter: function ( optionalTarget ) { + + var result = optionalTarget || new Vector2(); + return this.isEmpty() ? result.set( 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + + }, + + getSize: function ( optionalTarget ) { + + var result = optionalTarget || new Vector2(); + return this.isEmpty() ? result.set( 0, 0 ) : result.subVectors( this.max, this.min ); + + }, + + expandByPoint: function ( point ) { + + this.min.min( point ); + this.max.max( point ); + + return this; + + }, + + expandByVector: function ( vector ) { + + this.min.sub( vector ); + this.max.add( vector ); + + return this; + + }, + + expandByScalar: function ( scalar ) { + + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); + + return this; + + }, + + containsPoint: function ( point ) { + + return point.x < this.min.x || point.x > this.max.x || + point.y < this.min.y || point.y > this.max.y ? false : true; + + }, + + containsBox: function ( box ) { + + return this.min.x <= box.min.x && box.max.x <= this.max.x && + this.min.y <= box.min.y && box.max.y <= this.max.y; + + }, + + getParameter: function ( point, optionalTarget ) { + + // This can potentially have a divide by zero if the box + // has a size dimension of 0. + + var result = optionalTarget || new Vector2(); + + return result.set( + ( point.x - this.min.x ) / ( this.max.x - this.min.x ), + ( point.y - this.min.y ) / ( this.max.y - this.min.y ) + ); + + }, + + intersectsBox: function ( box ) { + + // using 6 splitting planes to rule out intersections. + return box.max.x < this.min.x || box.min.x > this.max.x || + box.max.y < this.min.y || box.min.y > this.max.y ? false : true; + + }, + + clampPoint: function ( point, optionalTarget ) { + + var result = optionalTarget || new Vector2(); + return result.copy( point ).clamp( this.min, this.max ); + + }, + + distanceToPoint: function () { + + var v1 = new Vector2(); + + return function distanceToPoint( point ) { + + var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); + return clampedPoint.sub( point ).length(); + + }; + + }(), + + intersect: function ( box ) { + + this.min.max( box.min ); + this.max.min( box.max ); + + return this; + + }, + + union: function ( box ) { + + this.min.min( box.min ); + this.max.max( box.max ); + + return this; + + }, + + translate: function ( offset ) { + + this.min.add( offset ); + this.max.add( offset ); + + return this; + + }, + + equals: function ( box ) { + + return box.min.equals( this.min ) && box.max.equals( this.max ); + + } + +}; + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +function LensFlarePlugin( renderer, flares ) { + + var gl = renderer.context; + var state = renderer.state; + + var vertexBuffer, elementBuffer; + var shader, program, attributes, uniforms; + + var tempTexture, occlusionTexture; + + function init() { + + var vertices = new Float32Array( [ + - 1, - 1, 0, 0, + 1, - 1, 1, 0, + 1, 1, 1, 1, + - 1, 1, 0, 1 + ] ); + + var faces = new Uint16Array( [ + 0, 1, 2, + 0, 2, 3 + ] ); + + // buffers + + vertexBuffer = gl.createBuffer(); + elementBuffer = gl.createBuffer(); + + gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); + gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); + + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); + gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW ); + + // textures + + tempTexture = gl.createTexture(); + occlusionTexture = gl.createTexture(); + + state.bindTexture( gl.TEXTURE_2D, tempTexture ); + gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, 16, 16, 0, gl.RGB, gl.UNSIGNED_BYTE, null ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); + + state.bindTexture( gl.TEXTURE_2D, occlusionTexture ); + gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); + + shader = { + + vertexShader: [ + + "uniform lowp int renderType;", + + "uniform vec3 screenPosition;", + "uniform vec2 scale;", + "uniform float rotation;", + + "uniform sampler2D occlusionMap;", + + "attribute vec2 position;", + "attribute vec2 uv;", + + "varying vec2 vUV;", + "varying float vVisibility;", + + "void main() {", + + "vUV = uv;", + + "vec2 pos = position;", + + "if ( renderType == 2 ) {", + + "vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );", + + "vVisibility = visibility.r / 9.0;", + "vVisibility *= 1.0 - visibility.g / 9.0;", + "vVisibility *= visibility.b / 9.0;", + "vVisibility *= 1.0 - visibility.a / 9.0;", + + "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", + "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", + + "}", + + "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", + + "}" + + ].join( "\n" ), + + fragmentShader: [ + + "uniform lowp int renderType;", + + "uniform sampler2D map;", + "uniform float opacity;", + "uniform vec3 color;", + + "varying vec2 vUV;", + "varying float vVisibility;", + + "void main() {", + + // pink square + + "if ( renderType == 0 ) {", + + "gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );", + + // restore + + "} else if ( renderType == 1 ) {", + + "gl_FragColor = texture2D( map, vUV );", + + // flare + + "} else {", + + "vec4 texture = texture2D( map, vUV );", + "texture.a *= opacity * vVisibility;", + "gl_FragColor = texture;", + "gl_FragColor.rgb *= color;", + + "}", + + "}" + + ].join( "\n" ) + + }; + + program = createProgram( shader ); + + attributes = { + vertex: gl.getAttribLocation ( program, "position" ), + uv: gl.getAttribLocation ( program, "uv" ) + }; + + uniforms = { + renderType: gl.getUniformLocation( program, "renderType" ), + map: gl.getUniformLocation( program, "map" ), + occlusionMap: gl.getUniformLocation( program, "occlusionMap" ), + opacity: gl.getUniformLocation( program, "opacity" ), + color: gl.getUniformLocation( program, "color" ), + scale: gl.getUniformLocation( program, "scale" ), + rotation: gl.getUniformLocation( program, "rotation" ), + screenPosition: gl.getUniformLocation( program, "screenPosition" ) + }; + + } + + /* + * Render lens flares + * Method: renders 16x16 0xff00ff-colored points scattered over the light source area, + * reads these back and calculates occlusion. + */ + + this.render = function ( scene, camera, viewport ) { + + if ( flares.length === 0 ) return; + + var tempPosition = new Vector3(); + + var invAspect = viewport.w / viewport.z, + halfViewportWidth = viewport.z * 0.5, + halfViewportHeight = viewport.w * 0.5; + + var size = 16 / viewport.w, + scale = new Vector2( size * invAspect, size ); + + var screenPosition = new Vector3( 1, 1, 0 ), + screenPositionPixels = new Vector2( 1, 1 ); + + var validArea = new Box2(); + + validArea.min.set( viewport.x, viewport.y ); + validArea.max.set( viewport.x + ( viewport.z - 16 ), viewport.y + ( viewport.w - 16 ) ); + + if ( program === undefined ) { + + init(); + + } + + gl.useProgram( program ); + + state.initAttributes(); + state.enableAttribute( attributes.vertex ); + state.enableAttribute( attributes.uv ); + state.disableUnusedAttributes(); + + // loop through all lens flares to update their occlusion and positions + // setup gl and common used attribs/uniforms + + gl.uniform1i( uniforms.occlusionMap, 0 ); + gl.uniform1i( uniforms.map, 1 ); + + gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); + gl.vertexAttribPointer( attributes.vertex, 2, gl.FLOAT, false, 2 * 8, 0 ); + gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 ); + + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); + + state.disable( gl.CULL_FACE ); + state.setDepthWrite( false ); + + for ( var i = 0, l = flares.length; i < l; i ++ ) { + + size = 16 / viewport.w; + scale.set( size * invAspect, size ); + + // calc object screen position + + var flare = flares[ i ]; + + tempPosition.set( flare.matrixWorld.elements[ 12 ], flare.matrixWorld.elements[ 13 ], flare.matrixWorld.elements[ 14 ] ); + + tempPosition.applyMatrix4( camera.matrixWorldInverse ); + tempPosition.applyMatrix4( camera.projectionMatrix ); + + // setup arrays for gl programs + + screenPosition.copy( tempPosition ); + + // horizontal and vertical coordinate of the lower left corner of the pixels to copy + + screenPositionPixels.x = viewport.x + ( screenPosition.x * halfViewportWidth ) + halfViewportWidth - 8; + screenPositionPixels.y = viewport.y + ( screenPosition.y * halfViewportHeight ) + halfViewportHeight - 8; + + // screen cull + + if ( validArea.containsPoint( screenPositionPixels ) === true ) { + + // save current RGB to temp texture + + state.activeTexture( gl.TEXTURE0 ); + state.bindTexture( gl.TEXTURE_2D, null ); + state.activeTexture( gl.TEXTURE1 ); + state.bindTexture( gl.TEXTURE_2D, tempTexture ); + gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 ); + + + // render pink quad + + gl.uniform1i( uniforms.renderType, 0 ); + gl.uniform2f( uniforms.scale, scale.x, scale.y ); + gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); + + state.disable( gl.BLEND ); + state.enable( gl.DEPTH_TEST ); + + gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); + + + // copy result to occlusionMap + + state.activeTexture( gl.TEXTURE0 ); + state.bindTexture( gl.TEXTURE_2D, occlusionTexture ); + gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 ); + + + // restore graphics + + gl.uniform1i( uniforms.renderType, 1 ); + state.disable( gl.DEPTH_TEST ); + + state.activeTexture( gl.TEXTURE1 ); + state.bindTexture( gl.TEXTURE_2D, tempTexture ); + gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); + + + // update object positions + + flare.positionScreen.copy( screenPosition ); + + if ( flare.customUpdateCallback ) { + + flare.customUpdateCallback( flare ); + + } else { + + flare.updateLensFlares(); + + } + + // render flares + + gl.uniform1i( uniforms.renderType, 2 ); + state.enable( gl.BLEND ); + + for ( var j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) { + + var sprite = flare.lensFlares[ j ]; + + if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) { + + screenPosition.x = sprite.x; + screenPosition.y = sprite.y; + screenPosition.z = sprite.z; + + size = sprite.size * sprite.scale / viewport.w; + + scale.x = size * invAspect; + scale.y = size; + + gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); + gl.uniform2f( uniforms.scale, scale.x, scale.y ); + gl.uniform1f( uniforms.rotation, sprite.rotation ); + + gl.uniform1f( uniforms.opacity, sprite.opacity ); + gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b ); + + state.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); + renderer.setTexture2D( sprite.texture, 1 ); + + gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); + + } + + } + + } + + } + + // restore gl + + state.enable( gl.CULL_FACE ); + state.enable( gl.DEPTH_TEST ); + state.setDepthWrite( true ); + + renderer.resetGLState(); + + }; + + function createProgram( shader ) { + + var program = gl.createProgram(); + + var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER ); + var vertexShader = gl.createShader( gl.VERTEX_SHADER ); + + var prefix = "precision " + renderer.getPrecision() + " float;\n"; + + gl.shaderSource( fragmentShader, prefix + shader.fragmentShader ); + gl.shaderSource( vertexShader, prefix + shader.vertexShader ); + + gl.compileShader( fragmentShader ); + gl.compileShader( vertexShader ); + + gl.attachShader( program, fragmentShader ); + gl.attachShader( program, vertexShader ); + + gl.linkProgram( program ); + + return program; + + } + +} + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +function SpritePlugin( renderer, sprites ) { + + var gl = renderer.context; + var state = renderer.state; + + var vertexBuffer, elementBuffer; + var program, attributes, uniforms; + + var texture; + + // decompose matrixWorld + + var spritePosition = new Vector3(); + var spriteRotation = new Quaternion(); + var spriteScale = new Vector3(); + + function init() { + + var vertices = new Float32Array( [ + - 0.5, - 0.5, 0, 0, + 0.5, - 0.5, 1, 0, + 0.5, 0.5, 1, 1, + - 0.5, 0.5, 0, 1 + ] ); + + var faces = new Uint16Array( [ + 0, 1, 2, + 0, 2, 3 + ] ); + + vertexBuffer = gl.createBuffer(); + elementBuffer = gl.createBuffer(); + + gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); + gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); + + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); + gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW ); + + program = createProgram(); + + attributes = { + position: gl.getAttribLocation ( program, 'position' ), + uv: gl.getAttribLocation ( program, 'uv' ) + }; + + uniforms = { + uvOffset: gl.getUniformLocation( program, 'uvOffset' ), + uvScale: gl.getUniformLocation( program, 'uvScale' ), + + rotation: gl.getUniformLocation( program, 'rotation' ), + scale: gl.getUniformLocation( program, 'scale' ), + + color: gl.getUniformLocation( program, 'color' ), + map: gl.getUniformLocation( program, 'map' ), + opacity: gl.getUniformLocation( program, 'opacity' ), + + modelViewMatrix: gl.getUniformLocation( program, 'modelViewMatrix' ), + projectionMatrix: gl.getUniformLocation( program, 'projectionMatrix' ), + + fogType: gl.getUniformLocation( program, 'fogType' ), + fogDensity: gl.getUniformLocation( program, 'fogDensity' ), + fogNear: gl.getUniformLocation( program, 'fogNear' ), + fogFar: gl.getUniformLocation( program, 'fogFar' ), + fogColor: gl.getUniformLocation( program, 'fogColor' ), + + alphaTest: gl.getUniformLocation( program, 'alphaTest' ) + }; + + var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); + canvas.width = 8; + canvas.height = 8; + + var context = canvas.getContext( '2d' ); + context.fillStyle = 'white'; + context.fillRect( 0, 0, 8, 8 ); + + texture = new Texture( canvas ); + texture.needsUpdate = true; + + } + + this.render = function ( scene, camera ) { + + if ( sprites.length === 0 ) return; + + // setup gl + + if ( program === undefined ) { + + init(); + + } + + gl.useProgram( program ); + + state.initAttributes(); + state.enableAttribute( attributes.position ); + state.enableAttribute( attributes.uv ); + state.disableUnusedAttributes(); + + state.disable( gl.CULL_FACE ); + state.enable( gl.BLEND ); + + gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); + gl.vertexAttribPointer( attributes.position, 2, gl.FLOAT, false, 2 * 8, 0 ); + gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 ); + + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); + + gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); + + state.activeTexture( gl.TEXTURE0 ); + gl.uniform1i( uniforms.map, 0 ); + + var oldFogType = 0; + var sceneFogType = 0; + var fog = scene.fog; + + if ( fog ) { + + gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b ); + + if ( fog.isFog ) { + + gl.uniform1f( uniforms.fogNear, fog.near ); + gl.uniform1f( uniforms.fogFar, fog.far ); + + gl.uniform1i( uniforms.fogType, 1 ); + oldFogType = 1; + sceneFogType = 1; + + } else if ( fog.isFogExp2 ) { + + gl.uniform1f( uniforms.fogDensity, fog.density ); + + gl.uniform1i( uniforms.fogType, 2 ); + oldFogType = 2; + sceneFogType = 2; + + } + + } else { + + gl.uniform1i( uniforms.fogType, 0 ); + oldFogType = 0; + sceneFogType = 0; + + } + + + // update positions and sort + + for ( var i = 0, l = sprites.length; i < l; i ++ ) { + + var sprite = sprites[ i ]; + + sprite.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld ); + sprite.z = - sprite.modelViewMatrix.elements[ 14 ]; + + } + + sprites.sort( painterSortStable ); + + // render all sprites + + var scale = []; + + for ( var i = 0, l = sprites.length; i < l; i ++ ) { + + var sprite = sprites[ i ]; + var material = sprite.material; + + if ( material.visible === false ) continue; + + gl.uniform1f( uniforms.alphaTest, material.alphaTest ); + gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite.modelViewMatrix.elements ); + + sprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale ); + + scale[ 0 ] = spriteScale.x; + scale[ 1 ] = spriteScale.y; + + var fogType = 0; + + if ( scene.fog && material.fog ) { + + fogType = sceneFogType; + + } + + if ( oldFogType !== fogType ) { + + gl.uniform1i( uniforms.fogType, fogType ); + oldFogType = fogType; + + } + + if ( material.map !== null ) { + + gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y ); + gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y ); + + } else { + + gl.uniform2f( uniforms.uvOffset, 0, 0 ); + gl.uniform2f( uniforms.uvScale, 1, 1 ); + + } + + gl.uniform1f( uniforms.opacity, material.opacity ); + gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b ); + + gl.uniform1f( uniforms.rotation, material.rotation ); + gl.uniform2fv( uniforms.scale, scale ); + + state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + state.setDepthTest( material.depthTest ); + state.setDepthWrite( material.depthWrite ); + + if ( material.map ) { + + renderer.setTexture2D( material.map, 0 ); + + } else { + + renderer.setTexture2D( texture, 0 ); + + } + + gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); + + } + + // restore gl + + state.enable( gl.CULL_FACE ); + + renderer.resetGLState(); + + }; + + function createProgram() { + + var program = gl.createProgram(); + + var vertexShader = gl.createShader( gl.VERTEX_SHADER ); + var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER ); + + gl.shaderSource( vertexShader, [ + + 'precision ' + renderer.getPrecision() + ' float;', + + 'uniform mat4 modelViewMatrix;', + 'uniform mat4 projectionMatrix;', + 'uniform float rotation;', + 'uniform vec2 scale;', + 'uniform vec2 uvOffset;', + 'uniform vec2 uvScale;', + + 'attribute vec2 position;', + 'attribute vec2 uv;', + + 'varying vec2 vUV;', + + 'void main() {', + + 'vUV = uvOffset + uv * uvScale;', + + 'vec2 alignedPosition = position * scale;', + + 'vec2 rotatedPosition;', + 'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;', + 'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;', + + 'vec4 finalPosition;', + + 'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );', + 'finalPosition.xy += rotatedPosition;', + 'finalPosition = projectionMatrix * finalPosition;', + + 'gl_Position = finalPosition;', + + '}' + + ].join( '\n' ) ); + + gl.shaderSource( fragmentShader, [ + + 'precision ' + renderer.getPrecision() + ' float;', + + 'uniform vec3 color;', + 'uniform sampler2D map;', + 'uniform float opacity;', + + 'uniform int fogType;', + 'uniform vec3 fogColor;', + 'uniform float fogDensity;', + 'uniform float fogNear;', + 'uniform float fogFar;', + 'uniform float alphaTest;', + + 'varying vec2 vUV;', + + 'void main() {', + + 'vec4 texture = texture2D( map, vUV );', + + 'if ( texture.a < alphaTest ) discard;', + + 'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );', + + 'if ( fogType > 0 ) {', + + 'float depth = gl_FragCoord.z / gl_FragCoord.w;', + 'float fogFactor = 0.0;', + + 'if ( fogType == 1 ) {', + + 'fogFactor = smoothstep( fogNear, fogFar, depth );', + + '} else {', + + 'const float LOG2 = 1.442695;', + 'fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );', + 'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );', + + '}', + + 'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );', + + '}', + + '}' + + ].join( '\n' ) ); + + gl.compileShader( vertexShader ); + gl.compileShader( fragmentShader ); + + gl.attachShader( program, vertexShader ); + gl.attachShader( program, fragmentShader ); + + gl.linkProgram( program ); + + return program; + + } + + function painterSortStable( a, b ) { + + if ( a.renderOrder !== b.renderOrder ) { + + return a.renderOrder - b.renderOrder; + + } else if ( a.z !== b.z ) { + + return b.z - a.z; + + } else { + + return b.id - a.id; + + } + + } + +} + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +var materialId = 0; + +function Material() { + + Object.defineProperty( this, 'id', { value: materialId ++ } ); + + this.uuid = _Math.generateUUID(); + + this.name = ''; + this.type = 'Material'; + + this.fog = true; + this.lights = true; + + this.blending = NormalBlending; + this.side = FrontSide; + this.shading = SmoothShading; // THREE.FlatShading, THREE.SmoothShading + this.vertexColors = NoColors; // THREE.NoColors, THREE.VertexColors, THREE.FaceColors + + this.opacity = 1; + this.transparent = false; + + this.blendSrc = SrcAlphaFactor; + this.blendDst = OneMinusSrcAlphaFactor; + this.blendEquation = AddEquation; + this.blendSrcAlpha = null; + this.blendDstAlpha = null; + this.blendEquationAlpha = null; + + this.depthFunc = LessEqualDepth; + this.depthTest = true; + this.depthWrite = true; + + this.clippingPlanes = null; + this.clipIntersection = false; + this.clipShadows = false; + + this.colorWrite = true; + + this.precision = null; // override the renderer's default precision for this material + + this.polygonOffset = false; + this.polygonOffsetFactor = 0; + this.polygonOffsetUnits = 0; + + this.alphaTest = 0; + this.premultipliedAlpha = false; + + this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer + + this.visible = true; + + this._needsUpdate = true; + +} + +Material.prototype = { + + constructor: Material, + + isMaterial: true, + + get needsUpdate() { + + return this._needsUpdate; + + }, + + set needsUpdate( value ) { + + if ( value === true ) this.update(); + this._needsUpdate = value; + + }, + + setValues: function ( values ) { + + if ( values === undefined ) return; + + for ( var key in values ) { + + var newValue = values[ key ]; + + if ( newValue === undefined ) { + + console.warn( "THREE.Material: '" + key + "' parameter is undefined." ); + continue; + + } + + var currentValue = this[ key ]; + + if ( currentValue === undefined ) { + + console.warn( "THREE." + this.type + ": '" + key + "' is not a property of this material." ); + continue; + + } + + if ( currentValue && currentValue.isColor ) { + + currentValue.set( newValue ); + + } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) { + + currentValue.copy( newValue ); + + } else if ( key === 'overdraw' ) { + + // ensure overdraw is backwards-compatible with legacy boolean type + this[ key ] = Number( newValue ); + + } else { + + this[ key ] = newValue; + + } + + } + + }, + + toJSON: function ( meta ) { + + var isRoot = meta === undefined; + + if ( isRoot ) { + + meta = { + textures: {}, + images: {} + }; + + } + + var data = { + metadata: { + version: 4.4, + type: 'Material', + generator: 'Material.toJSON' + } + }; + + // standard Material serialization + data.uuid = this.uuid; + data.type = this.type; + + if ( this.name !== '' ) data.name = this.name; + + if ( this.color && this.color.isColor ) data.color = this.color.getHex(); + + if ( this.roughness !== undefined ) data.roughness = this.roughness; + if ( this.metalness !== undefined ) data.metalness = this.metalness; + + if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex(); + if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex(); + if ( this.shininess !== undefined ) data.shininess = this.shininess; + if ( this.clearCoat !== undefined ) data.clearCoat = this.clearCoat; + if ( this.clearCoatRoughness !== undefined ) data.clearCoatRoughness = this.clearCoatRoughness; + + if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid; + if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid; + if ( this.lightMap && this.lightMap.isTexture ) data.lightMap = this.lightMap.toJSON( meta ).uuid; + if ( this.bumpMap && this.bumpMap.isTexture ) { + + data.bumpMap = this.bumpMap.toJSON( meta ).uuid; + data.bumpScale = this.bumpScale; + + } + if ( this.normalMap && this.normalMap.isTexture ) { + + data.normalMap = this.normalMap.toJSON( meta ).uuid; + data.normalScale = this.normalScale.toArray(); + + } + if ( this.displacementMap && this.displacementMap.isTexture ) { + + data.displacementMap = this.displacementMap.toJSON( meta ).uuid; + data.displacementScale = this.displacementScale; + data.displacementBias = this.displacementBias; + + } + if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid; + if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid; + + if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid; + if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid; + + if ( this.envMap && this.envMap.isTexture ) { + + data.envMap = this.envMap.toJSON( meta ).uuid; + data.reflectivity = this.reflectivity; // Scale behind envMap + + } + + if ( this.gradientMap && this.gradientMap.isTexture ) { + + data.gradientMap = this.gradientMap.toJSON( meta ).uuid; + + } + + if ( this.size !== undefined ) data.size = this.size; + if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation; + + if ( this.blending !== NormalBlending ) data.blending = this.blending; + if ( this.shading !== SmoothShading ) data.shading = this.shading; + if ( this.side !== FrontSide ) data.side = this.side; + if ( this.vertexColors !== NoColors ) data.vertexColors = this.vertexColors; + + if ( this.opacity < 1 ) data.opacity = this.opacity; + if ( this.transparent === true ) data.transparent = this.transparent; + + data.depthFunc = this.depthFunc; + data.depthTest = this.depthTest; + data.depthWrite = this.depthWrite; + + if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; + if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha; + if ( this.wireframe === true ) data.wireframe = this.wireframe; + if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; + if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap; + if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin; + + data.skinning = this.skinning; + data.morphTargets = this.morphTargets; + + // TODO: Copied from Object3D.toJSON + + function extractFromCache( cache ) { + + var values = []; + + for ( var key in cache ) { + + var data = cache[ key ]; + delete data.metadata; + values.push( data ); + + } + + return values; + + } + + if ( isRoot ) { + + var textures = extractFromCache( meta.textures ); + var images = extractFromCache( meta.images ); + + if ( textures.length > 0 ) data.textures = textures; + if ( images.length > 0 ) data.images = images; + + } + + return data; + + }, + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + copy: function ( source ) { + + this.name = source.name; + + this.fog = source.fog; + this.lights = source.lights; + + this.blending = source.blending; + this.side = source.side; + this.shading = source.shading; + this.vertexColors = source.vertexColors; + + this.opacity = source.opacity; + this.transparent = source.transparent; + + this.blendSrc = source.blendSrc; + this.blendDst = source.blendDst; + this.blendEquation = source.blendEquation; + this.blendSrcAlpha = source.blendSrcAlpha; + this.blendDstAlpha = source.blendDstAlpha; + this.blendEquationAlpha = source.blendEquationAlpha; + + this.depthFunc = source.depthFunc; + this.depthTest = source.depthTest; + this.depthWrite = source.depthWrite; + + this.colorWrite = source.colorWrite; + + this.precision = source.precision; + + this.polygonOffset = source.polygonOffset; + this.polygonOffsetFactor = source.polygonOffsetFactor; + this.polygonOffsetUnits = source.polygonOffsetUnits; + + this.alphaTest = source.alphaTest; + + this.premultipliedAlpha = source.premultipliedAlpha; + + this.overdraw = source.overdraw; + + this.visible = source.visible; + this.clipShadows = source.clipShadows; + this.clipIntersection = source.clipIntersection; + + var srcPlanes = source.clippingPlanes, + dstPlanes = null; + + if ( srcPlanes !== null ) { + + var n = srcPlanes.length; + dstPlanes = new Array( n ); + + for ( var i = 0; i !== n; ++ i ) + dstPlanes[ i ] = srcPlanes[ i ].clone(); + + } + + this.clippingPlanes = dstPlanes; + + return this; + + }, + + update: function () { + + this.dispatchEvent( { type: 'update' } ); + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +}; + +Object.assign( Material.prototype, EventDispatcher.prototype ); + +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * defines: { "label" : "value" }, + * uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } }, + * + * fragmentShader: , + * vertexShader: , + * + * wireframe: , + * wireframeLinewidth: , + * + * lights: , + * + * skinning: , + * morphTargets: , + * morphNormals: + * } + */ + +function ShaderMaterial( parameters ) { + + Material.call( this ); + + this.type = 'ShaderMaterial'; + + this.defines = {}; + this.uniforms = {}; + + this.vertexShader = 'void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}'; + this.fragmentShader = 'void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}'; + + this.linewidth = 1; + + this.wireframe = false; + this.wireframeLinewidth = 1; + + this.fog = false; // set to use scene fog + this.lights = false; // set to use scene lights + this.clipping = false; // set to use user-defined clipping planes + + this.skinning = false; // set to use skinning attribute streams + this.morphTargets = false; // set to use morph targets + this.morphNormals = false; // set to use morph normals + + this.extensions = { + derivatives: false, // set to use derivatives + fragDepth: false, // set to use fragment depth values + drawBuffers: false, // set to use draw buffers + shaderTextureLOD: false // set to use shader texture LOD + }; + + // When rendered geometry doesn't include these attributes but the material does, + // use these default values in WebGL. This avoids errors when buffer data is missing. + this.defaultAttributeValues = { + 'color': [ 1, 1, 1 ], + 'uv': [ 0, 0 ], + 'uv2': [ 0, 0 ] + }; + + this.index0AttributeName = undefined; + + if ( parameters !== undefined ) { + + if ( parameters.attributes !== undefined ) { + + console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' ); + + } + + this.setValues( parameters ); + + } + +} + +ShaderMaterial.prototype = Object.create( Material.prototype ); +ShaderMaterial.prototype.constructor = ShaderMaterial; + +ShaderMaterial.prototype.isShaderMaterial = true; + +ShaderMaterial.prototype.copy = function ( source ) { + + Material.prototype.copy.call( this, source ); + + this.fragmentShader = source.fragmentShader; + this.vertexShader = source.vertexShader; + + this.uniforms = UniformsUtils.clone( source.uniforms ); + + this.defines = source.defines; + + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + + this.lights = source.lights; + this.clipping = source.clipping; + + this.skinning = source.skinning; + + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; + + this.extensions = source.extensions; + + return this; + +}; + +ShaderMaterial.prototype.toJSON = function ( meta ) { + + var data = Material.prototype.toJSON.call( this, meta ); + + data.uniforms = this.uniforms; + data.vertexShader = this.vertexShader; + data.fragmentShader = this.fragmentShader; + + return data; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author bhouston / https://clara.io + * @author WestLangley / http://github.com/WestLangley + * + * parameters = { + * + * opacity: , + * + * map: new THREE.Texture( ), + * + * alphaMap: new THREE.Texture( ), + * + * displacementMap: new THREE.Texture( ), + * displacementScale: , + * displacementBias: , + * + * wireframe: , + * wireframeLinewidth: + * } + */ + +function MeshDepthMaterial( parameters ) { + + Material.call( this ); + + this.type = 'MeshDepthMaterial'; + + this.depthPacking = BasicDepthPacking; + + this.skinning = false; + this.morphTargets = false; + + this.map = null; + + this.alphaMap = null; + + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; + + this.wireframe = false; + this.wireframeLinewidth = 1; + + this.fog = false; + this.lights = false; + + this.setValues( parameters ); + +} + +MeshDepthMaterial.prototype = Object.create( Material.prototype ); +MeshDepthMaterial.prototype.constructor = MeshDepthMaterial; + +MeshDepthMaterial.prototype.isMeshDepthMaterial = true; + +MeshDepthMaterial.prototype.copy = function ( source ) { + + Material.prototype.copy.call( this, source ); + + this.depthPacking = source.depthPacking; + + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + + this.map = source.map; + + this.alphaMap = source.alphaMap; + + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; + + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + + return this; + +}; + +/** + * @author bhouston / http://clara.io + * @author WestLangley / http://github.com/WestLangley + */ + +function Box3( min, max ) { + + this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity ); + this.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity ); + +} + +Box3.prototype = { + + constructor: Box3, + + isBox3: true, + + set: function ( min, max ) { + + this.min.copy( min ); + this.max.copy( max ); + + return this; + + }, + + setFromArray: function ( array ) { + + var minX = + Infinity; + var minY = + Infinity; + var minZ = + Infinity; + + var maxX = - Infinity; + var maxY = - Infinity; + var maxZ = - Infinity; + + for ( var i = 0, l = array.length; i < l; i += 3 ) { + + var x = array[ i ]; + var y = array[ i + 1 ]; + var z = array[ i + 2 ]; + + if ( x < minX ) minX = x; + if ( y < minY ) minY = y; + if ( z < minZ ) minZ = z; + + if ( x > maxX ) maxX = x; + if ( y > maxY ) maxY = y; + if ( z > maxZ ) maxZ = z; + + } + + this.min.set( minX, minY, minZ ); + this.max.set( maxX, maxY, maxZ ); + + return this; + + }, + + setFromBufferAttribute: function ( attribute ) { + + var minX = + Infinity; + var minY = + Infinity; + var minZ = + Infinity; + + var maxX = - Infinity; + var maxY = - Infinity; + var maxZ = - Infinity; + + for ( var i = 0, l = attribute.count; i < l; i ++ ) { + + var x = attribute.getX( i ); + var y = attribute.getY( i ); + var z = attribute.getZ( i ); + + if ( x < minX ) minX = x; + if ( y < minY ) minY = y; + if ( z < minZ ) minZ = z; + + if ( x > maxX ) maxX = x; + if ( y > maxY ) maxY = y; + if ( z > maxZ ) maxZ = z; + + } + + this.min.set( minX, minY, minZ ); + this.max.set( maxX, maxY, maxZ ); + + return this; + + }, + + setFromPoints: function ( points ) { + + this.makeEmpty(); + + for ( var i = 0, il = points.length; i < il; i ++ ) { + + this.expandByPoint( points[ i ] ); + + } + + return this; + + }, + + setFromCenterAndSize: function () { + + var v1 = new Vector3(); + + return function setFromCenterAndSize( center, size ) { + + var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); + + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); + + return this; + + }; + + }(), + + setFromObject: function ( object ) { + + this.makeEmpty(); + + return this.expandByObject( object ); + + }, + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + copy: function ( box ) { + + this.min.copy( box.min ); + this.max.copy( box.max ); + + return this; + + }, + + makeEmpty: function () { + + this.min.x = this.min.y = this.min.z = + Infinity; + this.max.x = this.max.y = this.max.z = - Infinity; + + return this; + + }, + + isEmpty: function () { + + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); + + }, + + getCenter: function ( optionalTarget ) { + + var result = optionalTarget || new Vector3(); + return this.isEmpty() ? result.set( 0, 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + + }, + + getSize: function ( optionalTarget ) { + + var result = optionalTarget || new Vector3(); + return this.isEmpty() ? result.set( 0, 0, 0 ) : result.subVectors( this.max, this.min ); + + }, + + expandByPoint: function ( point ) { + + this.min.min( point ); + this.max.max( point ); + + return this; + + }, + + expandByVector: function ( vector ) { + + this.min.sub( vector ); + this.max.add( vector ); + + return this; + + }, + + expandByScalar: function ( scalar ) { + + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); + + return this; + + }, + + expandByObject: function () { + + // Computes the world-axis-aligned bounding box of an object (including its children), + // accounting for both the object's, and children's, world transforms + + var v1 = new Vector3(); + + return function expandByObject( object ) { + + var scope = this; + + object.updateMatrixWorld( true ); + + object.traverse( function ( node ) { + + var i, l; + + var geometry = node.geometry; + + if ( geometry !== undefined ) { + + if ( geometry.isGeometry ) { + + var vertices = geometry.vertices; + + for ( i = 0, l = vertices.length; i < l; i ++ ) { + + v1.copy( vertices[ i ] ); + v1.applyMatrix4( node.matrixWorld ); + + scope.expandByPoint( v1 ); + + } + + } else if ( geometry.isBufferGeometry ) { + + var attribute = geometry.attributes.position; + + if ( attribute !== undefined ) { + + for ( i = 0, l = attribute.count; i < l; i ++ ) { + + v1.fromBufferAttribute( attribute, i ).applyMatrix4( node.matrixWorld ); + + scope.expandByPoint( v1 ); + + } + + } + + } + + } + + } ); + + return this; + + }; + + }(), + + containsPoint: function ( point ) { + + return point.x < this.min.x || point.x > this.max.x || + point.y < this.min.y || point.y > this.max.y || + point.z < this.min.z || point.z > this.max.z ? false : true; + + }, + + containsBox: function ( box ) { + + return this.min.x <= box.min.x && box.max.x <= this.max.x && + this.min.y <= box.min.y && box.max.y <= this.max.y && + this.min.z <= box.min.z && box.max.z <= this.max.z; + + }, + + getParameter: function ( point, optionalTarget ) { + + // This can potentially have a divide by zero if the box + // has a size dimension of 0. + + var result = optionalTarget || new Vector3(); + + return result.set( + ( point.x - this.min.x ) / ( this.max.x - this.min.x ), + ( point.y - this.min.y ) / ( this.max.y - this.min.y ), + ( point.z - this.min.z ) / ( this.max.z - this.min.z ) + ); + + }, + + intersectsBox: function ( box ) { + + // using 6 splitting planes to rule out intersections. + return box.max.x < this.min.x || box.min.x > this.max.x || + box.max.y < this.min.y || box.min.y > this.max.y || + box.max.z < this.min.z || box.min.z > this.max.z ? false : true; + + }, + + intersectsSphere: ( function () { + + var closestPoint; + + return function intersectsSphere( sphere ) { + + if ( closestPoint === undefined ) closestPoint = new Vector3(); + + // Find the point on the AABB closest to the sphere center. + this.clampPoint( sphere.center, closestPoint ); + + // If that point is inside the sphere, the AABB and sphere intersect. + return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); + + }; + + } )(), + + intersectsPlane: function ( plane ) { + + // We compute the minimum and maximum dot product values. If those values + // are on the same side (back or front) of the plane, then there is no intersection. + + var min, max; + + if ( plane.normal.x > 0 ) { + + min = plane.normal.x * this.min.x; + max = plane.normal.x * this.max.x; + + } else { + + min = plane.normal.x * this.max.x; + max = plane.normal.x * this.min.x; + + } + + if ( plane.normal.y > 0 ) { + + min += plane.normal.y * this.min.y; + max += plane.normal.y * this.max.y; + + } else { + + min += plane.normal.y * this.max.y; + max += plane.normal.y * this.min.y; + + } + + if ( plane.normal.z > 0 ) { + + min += plane.normal.z * this.min.z; + max += plane.normal.z * this.max.z; + + } else { + + min += plane.normal.z * this.max.z; + max += plane.normal.z * this.min.z; + + } + + return ( min <= plane.constant && max >= plane.constant ); + + }, + + clampPoint: function ( point, optionalTarget ) { + + var result = optionalTarget || new Vector3(); + return result.copy( point ).clamp( this.min, this.max ); + + }, + + distanceToPoint: function () { + + var v1 = new Vector3(); + + return function distanceToPoint( point ) { + + var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); + return clampedPoint.sub( point ).length(); + + }; + + }(), + + getBoundingSphere: function () { + + var v1 = new Vector3(); + + return function getBoundingSphere( optionalTarget ) { + + var result = optionalTarget || new Sphere(); + + this.getCenter( result.center ); + + result.radius = this.getSize( v1 ).length() * 0.5; + + return result; + + }; + + }(), + + intersect: function ( box ) { + + this.min.max( box.min ); + this.max.min( box.max ); + + // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values. + if( this.isEmpty() ) this.makeEmpty(); + + return this; + + }, + + union: function ( box ) { + + this.min.min( box.min ); + this.max.max( box.max ); + + return this; + + }, + + applyMatrix4: function () { + + var points = [ + new Vector3(), + new Vector3(), + new Vector3(), + new Vector3(), + new Vector3(), + new Vector3(), + new Vector3(), + new Vector3() + ]; + + return function applyMatrix4( matrix ) { + + // transform of empty box is an empty box. + if( this.isEmpty() ) return this; + + // NOTE: I am using a binary pattern to specify all 2^3 combinations below + points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 + points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 + points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 + points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 + points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 + points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 + points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 + points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 + + this.setFromPoints( points ); + + return this; + + }; + + }(), + + translate: function ( offset ) { + + this.min.add( offset ); + this.max.add( offset ); + + return this; + + }, + + equals: function ( box ) { + + return box.min.equals( this.min ) && box.max.equals( this.max ); + + } + +}; + +/** + * @author bhouston / http://clara.io + * @author mrdoob / http://mrdoob.com/ + */ + +function Sphere( center, radius ) { + + this.center = ( center !== undefined ) ? center : new Vector3(); + this.radius = ( radius !== undefined ) ? radius : 0; + +} + +Sphere.prototype = { + + constructor: Sphere, + + set: function ( center, radius ) { + + this.center.copy( center ); + this.radius = radius; + + return this; + + }, + + setFromPoints: function () { + + var box; + + return function setFromPoints( points, optionalCenter ) { + + if ( box === undefined ) box = new Box3(); // see #10547 + + var center = this.center; + + if ( optionalCenter !== undefined ) { + + center.copy( optionalCenter ); + + } else { + + box.setFromPoints( points ).getCenter( center ); + + } + + var maxRadiusSq = 0; + + for ( var i = 0, il = points.length; i < il; i ++ ) { + + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); + + } + + this.radius = Math.sqrt( maxRadiusSq ); + + return this; + + }; + + }(), + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + copy: function ( sphere ) { + + this.center.copy( sphere.center ); + this.radius = sphere.radius; + + return this; + + }, + + empty: function () { + + return ( this.radius <= 0 ); + + }, + + containsPoint: function ( point ) { + + return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); + + }, + + distanceToPoint: function ( point ) { + + return ( point.distanceTo( this.center ) - this.radius ); + + }, + + intersectsSphere: function ( sphere ) { + + var radiusSum = this.radius + sphere.radius; + + return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); + + }, + + intersectsBox: function ( box ) { + + return box.intersectsSphere( this ); + + }, + + intersectsPlane: function ( plane ) { + + // We use the following equation to compute the signed distance from + // the center of the sphere to the plane. + // + // distance = q * n - d + // + // If this distance is greater than the radius of the sphere, + // then there is no intersection. + + return Math.abs( this.center.dot( plane.normal ) - plane.constant ) <= this.radius; + + }, + + clampPoint: function ( point, optionalTarget ) { + + var deltaLengthSq = this.center.distanceToSquared( point ); + + var result = optionalTarget || new Vector3(); + + result.copy( point ); + + if ( deltaLengthSq > ( this.radius * this.radius ) ) { + + result.sub( this.center ).normalize(); + result.multiplyScalar( this.radius ).add( this.center ); + + } + + return result; + + }, + + getBoundingBox: function ( optionalTarget ) { + + var box = optionalTarget || new Box3(); + + box.set( this.center, this.center ); + box.expandByScalar( this.radius ); + + return box; + + }, + + applyMatrix4: function ( matrix ) { + + this.center.applyMatrix4( matrix ); + this.radius = this.radius * matrix.getMaxScaleOnAxis(); + + return this; + + }, + + translate: function ( offset ) { + + this.center.add( offset ); + + return this; + + }, + + equals: function ( sphere ) { + + return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); + + } + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + * @author bhouston / http://clara.io + * @author tschw + */ + +function Matrix3() { + + this.elements = new Float32Array( [ + + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 + + ] ); + + if ( arguments.length > 0 ) { + + console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' ); + + } + +} + +Matrix3.prototype = { + + constructor: Matrix3, + + isMatrix3: true, + + set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { + + var te = this.elements; + + te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31; + te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32; + te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33; + + return this; + + }, + + identity: function () { + + this.set( + + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 + + ); + + return this; + + }, + + clone: function () { + + return new this.constructor().fromArray( this.elements ); + + }, + + copy: function ( m ) { + + var me = m.elements; + + this.set( + + me[ 0 ], me[ 3 ], me[ 6 ], + me[ 1 ], me[ 4 ], me[ 7 ], + me[ 2 ], me[ 5 ], me[ 8 ] + + ); + + return this; + + }, + + setFromMatrix4: function( m ) { + + var me = m.elements; + + this.set( + + me[ 0 ], me[ 4 ], me[ 8 ], + me[ 1 ], me[ 5 ], me[ 9 ], + me[ 2 ], me[ 6 ], me[ 10 ] + + ); + + return this; + + }, + + applyToBufferAttribute: function () { + + var v1; + + return function applyToBufferAttribute( attribute ) { + + if ( v1 === undefined ) v1 = new Vector3(); + + for ( var i = 0, l = attribute.count; i < l; i ++ ) { + + v1.x = attribute.getX( i ); + v1.y = attribute.getY( i ); + v1.z = attribute.getZ( i ); + + v1.applyMatrix3( this ); + + attribute.setXYZ( i, v1.x, v1.y, v1.z ); + + } + + return attribute; + + }; + + }(), + + multiplyScalar: function ( s ) { + + var te = this.elements; + + te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s; + te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s; + te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s; + + return this; + + }, + + determinant: function () { + + var te = this.elements; + + var a = te[ 0 ], b = te[ 1 ], c = te[ 2 ], + d = te[ 3 ], e = te[ 4 ], f = te[ 5 ], + g = te[ 6 ], h = te[ 7 ], i = te[ 8 ]; + + return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; + + }, + + getInverse: function ( matrix, throwOnDegenerate ) { + + if ( matrix && matrix.isMatrix4 ) { + + console.error( "THREE.Matrix3.getInverse no longer takes a Matrix4 argument." ); + + } + + var me = matrix.elements, + te = this.elements, + + n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], + n12 = me[ 3 ], n22 = me[ 4 ], n32 = me[ 5 ], + n13 = me[ 6 ], n23 = me[ 7 ], n33 = me[ 8 ], + + t11 = n33 * n22 - n32 * n23, + t12 = n32 * n13 - n33 * n12, + t13 = n23 * n12 - n22 * n13, + + det = n11 * t11 + n21 * t12 + n31 * t13; + + if ( det === 0 ) { + + var msg = "THREE.Matrix3.getInverse(): can't invert matrix, determinant is 0"; + + if ( throwOnDegenerate === true ) { + + throw new Error( msg ); + + } else { + + console.warn( msg ); + + } + + return this.identity(); + } + + var detInv = 1 / det; + + te[ 0 ] = t11 * detInv; + te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv; + te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv; + + te[ 3 ] = t12 * detInv; + te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv; + te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv; + + te[ 6 ] = t13 * detInv; + te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv; + te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv; + + return this; + + }, + + transpose: function () { + + var tmp, m = this.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; + + }, + + getNormalMatrix: function ( matrix4 ) { + + return this.setFromMatrix4( matrix4 ).getInverse( this ).transpose(); + + }, + + transposeIntoArray: function ( r ) { + + var m = this.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; + + }, + + fromArray: function ( array, offset ) { + + if ( offset === undefined ) offset = 0; + + for( var i = 0; i < 9; i ++ ) { + + this.elements[ i ] = array[ i + offset ]; + + } + + return this; + + }, + + toArray: function ( array, offset ) { + + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; + + var te = this.elements; + + array[ offset ] = te[ 0 ]; + array[ offset + 1 ] = te[ 1 ]; + array[ offset + 2 ] = te[ 2 ]; + + array[ offset + 3 ] = te[ 3 ]; + array[ offset + 4 ] = te[ 4 ]; + array[ offset + 5 ] = te[ 5 ]; + + array[ offset + 6 ] = te[ 6 ]; + array[ offset + 7 ] = te[ 7 ]; + array[ offset + 8 ] = te[ 8 ]; + + return array; + + } + +}; + +/** + * @author bhouston / http://clara.io + */ + +function Plane( normal, constant ) { + + this.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 ); + this.constant = ( constant !== undefined ) ? constant : 0; + +} + +Plane.prototype = { + + constructor: Plane, + + set: function ( normal, constant ) { + + this.normal.copy( normal ); + this.constant = constant; + + return this; + + }, + + setComponents: function ( x, y, z, w ) { + + this.normal.set( x, y, z ); + this.constant = w; + + return this; + + }, + + setFromNormalAndCoplanarPoint: function ( normal, point ) { + + this.normal.copy( normal ); + this.constant = - point.dot( this.normal ); // must be this.normal, not normal, as this.normal is normalized + + return this; + + }, + + setFromCoplanarPoints: function () { + + var v1 = new Vector3(); + var v2 = new Vector3(); + + return function setFromCoplanarPoints( a, b, c ) { + + var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize(); + + // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? + + this.setFromNormalAndCoplanarPoint( normal, a ); + + return this; + + }; + + }(), + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + copy: function ( plane ) { + + this.normal.copy( plane.normal ); + this.constant = plane.constant; + + return this; + + }, + + normalize: function () { + + // Note: will lead to a divide by zero if the plane is invalid. + + var inverseNormalLength = 1.0 / this.normal.length(); + this.normal.multiplyScalar( inverseNormalLength ); + this.constant *= inverseNormalLength; + + return this; + + }, + + negate: function () { + + this.constant *= - 1; + this.normal.negate(); + + return this; + + }, + + distanceToPoint: function ( point ) { + + return this.normal.dot( point ) + this.constant; + + }, + + distanceToSphere: function ( sphere ) { + + return this.distanceToPoint( sphere.center ) - sphere.radius; + + }, + + projectPoint: function ( point, optionalTarget ) { + + return this.orthoPoint( point, optionalTarget ).sub( point ).negate(); + + }, + + orthoPoint: function ( point, optionalTarget ) { + + var perpendicularMagnitude = this.distanceToPoint( point ); + + var result = optionalTarget || new Vector3(); + return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude ); + + }, + + intersectLine: function () { + + var v1 = new Vector3(); + + return function intersectLine( line, optionalTarget ) { + + var result = optionalTarget || new Vector3(); + + var direction = line.delta( v1 ); + + var denominator = this.normal.dot( direction ); + + if ( denominator === 0 ) { + + // line is coplanar, return origin + if ( this.distanceToPoint( line.start ) === 0 ) { + + return result.copy( line.start ); + + } + + // Unsure if this is the correct method to handle this case. + return undefined; + + } + + var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; + + if ( t < 0 || t > 1 ) { + + return undefined; + + } + + return result.copy( direction ).multiplyScalar( t ).add( line.start ); + + }; + + }(), + + intersectsLine: function ( line ) { + + // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. + + var startSign = this.distanceToPoint( line.start ); + var endSign = this.distanceToPoint( line.end ); + + return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); + + }, + + intersectsBox: function ( box ) { + + return box.intersectsPlane( this ); + + }, + + intersectsSphere: function ( sphere ) { + + return sphere.intersectsPlane( this ); + + }, + + coplanarPoint: function ( optionalTarget ) { + + var result = optionalTarget || new Vector3(); + return result.copy( this.normal ).multiplyScalar( - this.constant ); + + }, + + applyMatrix4: function () { + + var v1 = new Vector3(); + var m1 = new Matrix3(); + + return function applyMatrix4( matrix, optionalNormalMatrix ) { + + var referencePoint = this.coplanarPoint( v1 ).applyMatrix4( matrix ); + + // transform normal based on theory here: + // http://www.songho.ca/opengl/gl_normaltransform.html + var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix ); + var normal = this.normal.applyMatrix3( normalMatrix ).normalize(); + + // recalculate constant (like in setFromNormalAndCoplanarPoint) + this.constant = - referencePoint.dot( normal ); + + return this; + + }; + + }(), + + translate: function ( offset ) { + + this.constant = this.constant - offset.dot( this.normal ); + + return this; + + }, + + equals: function ( plane ) { + + return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author bhouston / http://clara.io + */ + +function Frustum( p0, p1, p2, p3, p4, p5 ) { + + this.planes = [ + + ( p0 !== undefined ) ? p0 : new Plane(), + ( p1 !== undefined ) ? p1 : new Plane(), + ( p2 !== undefined ) ? p2 : new Plane(), + ( p3 !== undefined ) ? p3 : new Plane(), + ( p4 !== undefined ) ? p4 : new Plane(), + ( p5 !== undefined ) ? p5 : new Plane() + + ]; + +} + +Frustum.prototype = { + + constructor: Frustum, + + set: function ( p0, p1, p2, p3, p4, p5 ) { + + var planes = this.planes; + + planes[ 0 ].copy( p0 ); + planes[ 1 ].copy( p1 ); + planes[ 2 ].copy( p2 ); + planes[ 3 ].copy( p3 ); + planes[ 4 ].copy( p4 ); + planes[ 5 ].copy( p5 ); + + return this; + + }, + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + copy: function ( frustum ) { + + var planes = this.planes; + + for ( var i = 0; i < 6; i ++ ) { + + planes[ i ].copy( frustum.planes[ i ] ); + + } + + return this; + + }, + + setFromMatrix: function ( m ) { + + var planes = this.planes; + var me = m.elements; + var me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ]; + var me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ]; + var me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ]; + var me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ]; + + planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); + planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); + planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); + planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); + planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); + planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); + + return this; + + }, + + intersectsObject: function () { + + var sphere = new Sphere(); + + return function intersectsObject( object ) { + + var geometry = object.geometry; + + if ( geometry.boundingSphere === null ) + geometry.computeBoundingSphere(); + + sphere.copy( geometry.boundingSphere ) + .applyMatrix4( object.matrixWorld ); + + return this.intersectsSphere( sphere ); + + }; + + }(), + + intersectsSprite: function () { + + var sphere = new Sphere(); + + return function intersectsSprite( sprite ) { + + sphere.center.set( 0, 0, 0 ); + sphere.radius = 0.7071067811865476; + sphere.applyMatrix4( sprite.matrixWorld ); + + return this.intersectsSphere( sphere ); + + }; + + }(), + + intersectsSphere: function ( sphere ) { + + var planes = this.planes; + var center = sphere.center; + var negRadius = - sphere.radius; + + for ( var i = 0; i < 6; i ++ ) { + + var distance = planes[ i ].distanceToPoint( center ); + + if ( distance < negRadius ) { + + return false; + + } + + } + + return true; + + }, + + intersectsBox: function () { + + var p1 = new Vector3(), + p2 = new Vector3(); + + return function intersectsBox( box ) { + + var planes = this.planes; + + for ( var i = 0; i < 6 ; i ++ ) { + + var plane = planes[ i ]; + + p1.x = plane.normal.x > 0 ? box.min.x : box.max.x; + p2.x = plane.normal.x > 0 ? box.max.x : box.min.x; + p1.y = plane.normal.y > 0 ? box.min.y : box.max.y; + p2.y = plane.normal.y > 0 ? box.max.y : box.min.y; + p1.z = plane.normal.z > 0 ? box.min.z : box.max.z; + p2.z = plane.normal.z > 0 ? box.max.z : box.min.z; + + var d1 = plane.distanceToPoint( p1 ); + var d2 = plane.distanceToPoint( p2 ); + + // if both outside plane, no intersection + + if ( d1 < 0 && d2 < 0 ) { + + return false; + + } + + } + + return true; + + }; + + }(), + + + containsPoint: function ( point ) { + + var planes = this.planes; + + for ( var i = 0; i < 6; i ++ ) { + + if ( planes[ i ].distanceToPoint( point ) < 0 ) { + + return false; + + } + + } + + return true; + + } + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ + +function WebGLShadowMap( _renderer, _lights, _objects, capabilities ) { + + var _gl = _renderer.context, + _state = _renderer.state, + _frustum = new Frustum(), + _projScreenMatrix = new Matrix4(), + + _lightShadows = _lights.shadows, + + _shadowMapSize = new Vector2(), + _maxShadowMapSize = new Vector2( capabilities.maxTextureSize, capabilities.maxTextureSize ), + + _lookTarget = new Vector3(), + _lightPositionWorld = new Vector3(), + + _renderList = [], + + _MorphingFlag = 1, + _SkinningFlag = 2, + + _NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1, + + _depthMaterials = new Array( _NumberOfMaterialVariants ), + _distanceMaterials = new Array( _NumberOfMaterialVariants ), + + _materialCache = {}; + + var cubeDirections = [ + new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ), + new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 ) + ]; + + var cubeUps = [ + new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), + new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 ) + ]; + + var cube2DViewPorts = [ + new Vector4(), new Vector4(), new Vector4(), + new Vector4(), new Vector4(), new Vector4() + ]; + + // init + + var depthMaterialTemplate = new MeshDepthMaterial(); + depthMaterialTemplate.depthPacking = RGBADepthPacking; + depthMaterialTemplate.clipping = true; + + var distanceShader = ShaderLib[ "distanceRGBA" ]; + var distanceUniforms = UniformsUtils.clone( distanceShader.uniforms ); + + for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) { + + var useMorphing = ( i & _MorphingFlag ) !== 0; + var useSkinning = ( i & _SkinningFlag ) !== 0; + + var depthMaterial = depthMaterialTemplate.clone(); + depthMaterial.morphTargets = useMorphing; + depthMaterial.skinning = useSkinning; + + _depthMaterials[ i ] = depthMaterial; + + var distanceMaterial = new ShaderMaterial( { + defines: { + 'USE_SHADOWMAP': '' + }, + uniforms: distanceUniforms, + vertexShader: distanceShader.vertexShader, + fragmentShader: distanceShader.fragmentShader, + morphTargets: useMorphing, + skinning: useSkinning, + clipping: true + } ); + + _distanceMaterials[ i ] = distanceMaterial; + + } + + // + + var scope = this; + + this.enabled = false; + + this.autoUpdate = true; + this.needsUpdate = false; + + this.type = PCFShadowMap; + + this.renderReverseSided = true; + this.renderSingleSided = true; + + this.render = function ( scene, camera ) { + + if ( scope.enabled === false ) return; + if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; + + if ( _lightShadows.length === 0 ) return; + + // Set GL state for depth map. + _state.buffers.color.setClear( 1, 1, 1, 1 ); + _state.disable( _gl.BLEND ); + _state.setDepthTest( true ); + _state.setScissorTest( false ); + + // render depth map + + var faceCount, isPointLight; + + for ( var i = 0, il = _lightShadows.length; i < il; i ++ ) { + + var light = _lightShadows[ i ]; + var shadow = light.shadow; + + if ( shadow === undefined ) { + + console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' ); + continue; + + } + + var shadowCamera = shadow.camera; + + _shadowMapSize.copy( shadow.mapSize ); + _shadowMapSize.min( _maxShadowMapSize ); + + if ( light && light.isPointLight ) { + + faceCount = 6; + isPointLight = true; + + var vpWidth = _shadowMapSize.x; + var vpHeight = _shadowMapSize.y; + + // These viewports map a cube-map onto a 2D texture with the + // following orientation: + // + // xzXZ + // y Y + // + // X - Positive x direction + // x - Negative x direction + // Y - Positive y direction + // y - Negative y direction + // Z - Positive z direction + // z - Negative z direction + + // positive X + cube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight ); + // negative X + cube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight ); + // positive Z + cube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight ); + // negative Z + cube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight ); + // positive Y + cube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight ); + // negative Y + cube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight ); + + _shadowMapSize.x *= 4.0; + _shadowMapSize.y *= 2.0; + + } else { + + faceCount = 1; + isPointLight = false; + + } + + if ( shadow.map === null ) { + + var pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat }; + + shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); + + shadowCamera.updateProjectionMatrix(); + + } + + if ( shadow.isSpotLightShadow ) { + + shadow.update( light ); + + } + + // TODO (abelnation / sam-g-steel): is this needed? + if (shadow && shadow.isRectAreaLightShadow ) { + + shadow.update( light ); + + } + + var shadowMap = shadow.map; + var shadowMatrix = shadow.matrix; + + _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); + shadowCamera.position.copy( _lightPositionWorld ); + + _renderer.setRenderTarget( shadowMap ); + _renderer.clear(); + + // render shadow map for each cube face (if omni-directional) or + // run a single pass if not + + for ( var face = 0; face < faceCount; face ++ ) { + + if ( isPointLight ) { + + _lookTarget.copy( shadowCamera.position ); + _lookTarget.add( cubeDirections[ face ] ); + shadowCamera.up.copy( cubeUps[ face ] ); + shadowCamera.lookAt( _lookTarget ); + + var vpDimensions = cube2DViewPorts[ face ]; + _state.viewport( vpDimensions ); + + } else { + + _lookTarget.setFromMatrixPosition( light.target.matrixWorld ); + shadowCamera.lookAt( _lookTarget ); + + } + + shadowCamera.updateMatrixWorld(); + shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld ); + + // compute shadow matrix + + shadowMatrix.set( + 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.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); + + // set object matrices & frustum culling + + _renderList.length = 0; + + projectObject( scene, camera, shadowCamera ); + + // render shadow map + // render regular objects + + for ( var j = 0, jl = _renderList.length; j < jl; j ++ ) { + + var object = _renderList[ j ]; + var geometry = _objects.update( object ); + var material = object.material; + + if ( material && material.isMultiMaterial ) { + + var groups = geometry.groups; + var materials = material.materials; + + for ( var k = 0, kl = groups.length; k < kl; k ++ ) { + + var group = groups[ k ]; + var groupMaterial = materials[ group.materialIndex ]; + + if ( groupMaterial.visible === true ) { + + var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld ); + _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); + + } + + } + + } else { + + var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld ); + _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); + + } + + } + + } + + } + + // Restore GL state. + var clearColor = _renderer.getClearColor(), + clearAlpha = _renderer.getClearAlpha(); + _renderer.setClearColor( clearColor, clearAlpha ); + + scope.needsUpdate = false; + + }; + + function getDepthMaterial( object, material, isPointLight, lightPositionWorld ) { + + var geometry = object.geometry; + + var result = null; + + var materialVariants = _depthMaterials; + var customMaterial = object.customDepthMaterial; + + if ( isPointLight ) { + + materialVariants = _distanceMaterials; + customMaterial = object.customDistanceMaterial; + + } + + if ( ! customMaterial ) { + + var useMorphing = false; + + if ( material.morphTargets ) { + + if ( geometry && geometry.isBufferGeometry ) { + + useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0; + + } else if ( geometry && geometry.isGeometry ) { + + useMorphing = geometry.morphTargets && geometry.morphTargets.length > 0; + + } + + } + + var useSkinning = object.isSkinnedMesh && material.skinning; + + var variantIndex = 0; + + if ( useMorphing ) variantIndex |= _MorphingFlag; + if ( useSkinning ) variantIndex |= _SkinningFlag; + + result = materialVariants[ variantIndex ]; + + } else { + + result = customMaterial; + + } + + if ( _renderer.localClippingEnabled && + material.clipShadows === true && + material.clippingPlanes.length !== 0 ) { + + // in this case we need a unique material instance reflecting the + // appropriate state + + var keyA = result.uuid, keyB = material.uuid; + + var materialsForVariant = _materialCache[ keyA ]; + + if ( materialsForVariant === undefined ) { + + materialsForVariant = {}; + _materialCache[ keyA ] = materialsForVariant; + + } + + var cachedMaterial = materialsForVariant[ keyB ]; + + if ( cachedMaterial === undefined ) { + + cachedMaterial = result.clone(); + materialsForVariant[ keyB ] = cachedMaterial; + + } + + result = cachedMaterial; + + } + + result.visible = material.visible; + result.wireframe = material.wireframe; + + var side = material.side; + + if ( scope.renderSingleSided && side == DoubleSide ) { + + side = FrontSide; + + } + + if ( scope.renderReverseSided ) { + + if ( side === FrontSide ) side = BackSide; + else if ( side === BackSide ) side = FrontSide; + + } + + result.side = side; + + result.clipShadows = material.clipShadows; + result.clippingPlanes = material.clippingPlanes; + + result.wireframeLinewidth = material.wireframeLinewidth; + result.linewidth = material.linewidth; + + if ( isPointLight && result.uniforms.lightPos !== undefined ) { + + result.uniforms.lightPos.value.copy( lightPositionWorld ); + + } + + return result; + + } + + function projectObject( object, camera, shadowCamera ) { + + if ( object.visible === false ) return; + + var visible = ( object.layers.mask & camera.layers.mask ) !== 0; + + if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) { + + if ( object.castShadow && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) { + + var material = object.material; + + if ( material.visible === true ) { + + object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + _renderList.push( object ); + + } + + } + + } + + var children = object.children; + + for ( var i = 0, l = children.length; i < l; i ++ ) { + + projectObject( children[ i ], camera, shadowCamera ); + + } + + } + +} + +/** + * @author bhouston / http://clara.io + */ + +function Ray( origin, direction ) { + + this.origin = ( origin !== undefined ) ? origin : new Vector3(); + this.direction = ( direction !== undefined ) ? direction : new Vector3(); + +} + +Ray.prototype = { + + constructor: Ray, + + set: function ( origin, direction ) { + + this.origin.copy( origin ); + this.direction.copy( direction ); + + return this; + + }, + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + copy: function ( ray ) { + + this.origin.copy( ray.origin ); + this.direction.copy( ray.direction ); + + return this; + + }, + + at: function ( t, optionalTarget ) { + + var result = optionalTarget || new Vector3(); + + return result.copy( this.direction ).multiplyScalar( t ).add( this.origin ); + + }, + + lookAt: function ( v ) { + + this.direction.copy( v ).sub( this.origin ).normalize(); + + return this; + + }, + + recast: function () { + + var v1 = new Vector3(); + + return function recast( t ) { + + this.origin.copy( this.at( t, v1 ) ); + + return this; + + }; + + }(), + + closestPointToPoint: function ( point, optionalTarget ) { + + var result = optionalTarget || new Vector3(); + result.subVectors( point, this.origin ); + var directionDistance = result.dot( this.direction ); + + if ( directionDistance < 0 ) { + + return result.copy( this.origin ); + + } + + return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + + }, + + distanceToPoint: function ( point ) { + + return Math.sqrt( this.distanceSqToPoint( point ) ); + + }, + + distanceSqToPoint: function () { + + var v1 = new Vector3(); + + return function distanceSqToPoint( point ) { + + var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction ); + + // point behind the ray + + if ( directionDistance < 0 ) { + + return this.origin.distanceToSquared( point ); + + } + + v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + + return v1.distanceToSquared( point ); + + }; + + }(), + + distanceSqToSegment: function () { + + var segCenter = new Vector3(); + var segDir = new Vector3(); + var diff = new Vector3(); + + return function distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { + + // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h + // It returns the min distance between the ray and the segment + // defined by v0 and v1 + // It can also set two optional targets : + // - The closest point on the ray + // - The closest point on the segment + + segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); + segDir.copy( v1 ).sub( v0 ).normalize(); + diff.copy( this.origin ).sub( segCenter ); + + var segExtent = v0.distanceTo( v1 ) * 0.5; + var a01 = - this.direction.dot( segDir ); + var b0 = diff.dot( this.direction ); + var b1 = - diff.dot( segDir ); + var c = diff.lengthSq(); + var det = Math.abs( 1 - a01 * a01 ); + var s0, s1, sqrDist, extDet; + + if ( det > 0 ) { + + // The ray and segment are not parallel. + + s0 = a01 * b1 - b0; + s1 = a01 * b0 - b1; + extDet = segExtent * det; + + if ( s0 >= 0 ) { + + if ( s1 >= - extDet ) { + + if ( s1 <= extDet ) { + + // region 0 + // Minimum at interior points of ray and segment. + + var invDet = 1 / det; + s0 *= invDet; + s1 *= invDet; + sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; + + } else { + + // region 1 + + s1 = segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + + } + + } else { + + // region 5 + + s1 = - segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + + } + + } else { + + if ( s1 <= - extDet ) { + + // region 4 + + s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); + s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + + } else if ( s1 <= extDet ) { + + // region 3 + + s0 = 0; + s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = s1 * ( s1 + 2 * b1 ) + c; + + } else { + + // region 2 + + s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); + s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + + } + + } + + } else { + + // Ray and segment are parallel. + + s1 = ( a01 > 0 ) ? - segExtent : segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + + } + + if ( optionalPointOnRay ) { + + optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin ); + + } + + if ( optionalPointOnSegment ) { + + optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter ); + + } + + return sqrDist; + + }; + + }(), + + intersectSphere: function () { + + var v1 = new Vector3(); + + return function intersectSphere( sphere, optionalTarget ) { + + v1.subVectors( sphere.center, this.origin ); + var tca = v1.dot( this.direction ); + var d2 = v1.dot( v1 ) - tca * tca; + var radius2 = sphere.radius * sphere.radius; + + if ( d2 > radius2 ) return null; + + var thc = Math.sqrt( radius2 - d2 ); + + // t0 = first intersect point - entrance on front of sphere + var t0 = tca - thc; + + // t1 = second intersect point - exit point on back of sphere + var t1 = tca + thc; + + // test to see if both t0 and t1 are behind the ray - if so, return null + if ( t0 < 0 && t1 < 0 ) return null; + + // test to see if t0 is behind the ray: + // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, + // in order to always return an intersect point that is in front of the ray. + if ( t0 < 0 ) return this.at( t1, optionalTarget ); + + // else t0 is in front of the ray, so return the first collision point scaled by t0 + return this.at( t0, optionalTarget ); + + }; + + }(), + + intersectsSphere: function ( sphere ) { + + return this.distanceToPoint( sphere.center ) <= sphere.radius; + + }, + + distanceToPlane: function ( plane ) { + + var denominator = plane.normal.dot( this.direction ); + + if ( denominator === 0 ) { + + // line is coplanar, return origin + if ( plane.distanceToPoint( this.origin ) === 0 ) { + + return 0; + + } + + // Null is preferable to undefined since undefined means.... it is undefined + + return null; + + } + + var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; + + // Return if the ray never intersects the plane + + return t >= 0 ? t : null; + + }, + + intersectPlane: function ( plane, optionalTarget ) { + + var t = this.distanceToPlane( plane ); + + if ( t === null ) { + + return null; + + } + + return this.at( t, optionalTarget ); + + }, + + + + intersectsPlane: function ( plane ) { + + // check if the ray lies on the plane first + + var distToPoint = plane.distanceToPoint( this.origin ); + + if ( distToPoint === 0 ) { + + return true; + + } + + var denominator = plane.normal.dot( this.direction ); + + if ( denominator * distToPoint < 0 ) { + + return true; + + } + + // ray origin is behind the plane (and is pointing behind it) + + return false; + + }, + + intersectBox: function ( box, optionalTarget ) { + + var tmin, tmax, tymin, tymax, tzmin, tzmax; + + var invdirx = 1 / this.direction.x, + invdiry = 1 / this.direction.y, + invdirz = 1 / this.direction.z; + + var origin = this.origin; + + if ( invdirx >= 0 ) { + + tmin = ( box.min.x - origin.x ) * invdirx; + tmax = ( box.max.x - origin.x ) * invdirx; + + } else { + + tmin = ( box.max.x - origin.x ) * invdirx; + tmax = ( box.min.x - origin.x ) * invdirx; + + } + + if ( invdiry >= 0 ) { + + tymin = ( box.min.y - origin.y ) * invdiry; + tymax = ( box.max.y - origin.y ) * invdiry; + + } else { + + tymin = ( box.max.y - origin.y ) * invdiry; + tymax = ( box.min.y - origin.y ) * invdiry; + + } + + if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; + + // These lines also handle the case where tmin or tmax is NaN + // (result of 0 * Infinity). x !== x returns true if x is NaN + + if ( tymin > tmin || tmin !== tmin ) tmin = tymin; + + if ( tymax < tmax || tmax !== tmax ) tmax = tymax; + + if ( invdirz >= 0 ) { + + tzmin = ( box.min.z - origin.z ) * invdirz; + tzmax = ( box.max.z - origin.z ) * invdirz; + + } else { + + tzmin = ( box.max.z - origin.z ) * invdirz; + tzmax = ( box.min.z - origin.z ) * invdirz; + + } + + if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; + + if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; + + if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; + + //return point closest to the ray (positive side) + + if ( tmax < 0 ) return null; + + return this.at( tmin >= 0 ? tmin : tmax, optionalTarget ); + + }, + + intersectsBox: ( function () { + + var v = new Vector3(); + + return function intersectsBox( box ) { + + return this.intersectBox( box, v ) !== null; + + }; + + } )(), + + intersectTriangle: function () { + + // Compute the offset origin, edges, and normal. + var diff = new Vector3(); + var edge1 = new Vector3(); + var edge2 = new Vector3(); + var normal = new Vector3(); + + return function intersectTriangle( a, b, c, backfaceCulling, optionalTarget ) { + + // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h + + edge1.subVectors( b, a ); + edge2.subVectors( c, a ); + normal.crossVectors( edge1, edge2 ); + + // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, + // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by + // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) + // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) + // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) + var DdN = this.direction.dot( normal ); + var sign; + + if ( DdN > 0 ) { + + if ( backfaceCulling ) return null; + sign = 1; + + } else if ( DdN < 0 ) { + + sign = - 1; + DdN = - DdN; + + } else { + + return null; + + } + + diff.subVectors( this.origin, a ); + var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) ); + + // b1 < 0, no intersection + if ( DdQxE2 < 0 ) { + + return null; + + } + + var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) ); + + // b2 < 0, no intersection + if ( DdE1xQ < 0 ) { + + return null; + + } + + // b1+b2 > 1, no intersection + if ( DdQxE2 + DdE1xQ > DdN ) { + + return null; + + } + + // Line intersects triangle, check if ray does. + var QdN = - sign * diff.dot( normal ); + + // t < 0, no intersection + if ( QdN < 0 ) { + + return null; + + } + + // Ray intersects triangle. + return this.at( QdN / DdN, optionalTarget ); + + }; + + }(), + + applyMatrix4: function ( matrix4 ) { + + this.direction.add( this.origin ).applyMatrix4( matrix4 ); + this.origin.applyMatrix4( matrix4 ); + this.direction.sub( this.origin ); + this.direction.normalize(); + + return this; + + }, + + equals: function ( ray ) { + + return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley + * @author bhouston / http://clara.io + */ + +function Euler( x, y, z, order ) { + + this._x = x || 0; + this._y = y || 0; + this._z = z || 0; + this._order = order || Euler.DefaultOrder; + +} + +Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; + +Euler.DefaultOrder = 'XYZ'; + +Euler.prototype = { + + constructor: Euler, + + isEuler: true, + + get x () { + + return this._x; + + }, + + set x ( value ) { + + this._x = value; + this.onChangeCallback(); + + }, + + get y () { + + return this._y; + + }, + + set y ( value ) { + + this._y = value; + this.onChangeCallback(); + + }, + + get z () { + + return this._z; + + }, + + set z ( value ) { + + this._z = value; + this.onChangeCallback(); + + }, + + get order () { + + return this._order; + + }, + + set order ( value ) { + + this._order = value; + this.onChangeCallback(); + + }, + + set: function ( x, y, z, order ) { + + this._x = x; + this._y = y; + this._z = z; + this._order = order || this._order; + + this.onChangeCallback(); + + return this; + + }, + + clone: function () { + + return new this.constructor( this._x, this._y, this._z, this._order ); + + }, + + copy: function ( euler ) { + + this._x = euler._x; + this._y = euler._y; + this._z = euler._z; + this._order = euler._order; + + this.onChangeCallback(); + + return this; + + }, + + setFromRotationMatrix: function ( m, order, update ) { + + var clamp = _Math.clamp; + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + var te = m.elements; + var m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ]; + var m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ]; + var m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; + + order = order || this._order; + + if ( order === 'XYZ' ) { + + this._y = Math.asin( clamp( m13, - 1, 1 ) ); + + if ( Math.abs( m13 ) < 0.99999 ) { + + this._x = Math.atan2( - m23, m33 ); + this._z = Math.atan2( - m12, m11 ); + + } else { + + this._x = Math.atan2( m32, m22 ); + this._z = 0; + + } + + } else if ( order === 'YXZ' ) { + + this._x = Math.asin( - clamp( m23, - 1, 1 ) ); + + if ( Math.abs( m23 ) < 0.99999 ) { + + this._y = Math.atan2( m13, m33 ); + this._z = Math.atan2( m21, m22 ); + + } else { + + this._y = Math.atan2( - m31, m11 ); + this._z = 0; + + } + + } else if ( order === 'ZXY' ) { + + this._x = Math.asin( clamp( m32, - 1, 1 ) ); + + if ( Math.abs( m32 ) < 0.99999 ) { + + this._y = Math.atan2( - m31, m33 ); + this._z = Math.atan2( - m12, m22 ); + + } else { + + this._y = 0; + this._z = Math.atan2( m21, m11 ); + + } + + } else if ( order === 'ZYX' ) { + + this._y = Math.asin( - clamp( m31, - 1, 1 ) ); + + if ( Math.abs( m31 ) < 0.99999 ) { + + this._x = Math.atan2( m32, m33 ); + this._z = Math.atan2( m21, m11 ); + + } else { + + this._x = 0; + this._z = Math.atan2( - m12, m22 ); + + } + + } else if ( order === 'YZX' ) { + + this._z = Math.asin( clamp( m21, - 1, 1 ) ); + + if ( Math.abs( m21 ) < 0.99999 ) { + + this._x = Math.atan2( - m23, m22 ); + this._y = Math.atan2( - m31, m11 ); + + } else { + + this._x = 0; + this._y = Math.atan2( m13, m33 ); + + } + + } else if ( order === 'XZY' ) { + + this._z = Math.asin( - clamp( m12, - 1, 1 ) ); + + if ( Math.abs( m12 ) < 0.99999 ) { + + this._x = Math.atan2( m32, m22 ); + this._y = Math.atan2( m13, m11 ); + + } else { + + this._x = Math.atan2( - m23, m33 ); + this._y = 0; + + } + + } else { + + console.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order ); + + } + + this._order = order; + + if ( update !== false ) this.onChangeCallback(); + + return this; + + }, + + setFromQuaternion: function () { + + var matrix; + + return function setFromQuaternion( q, order, update ) { + + if ( matrix === undefined ) matrix = new Matrix4(); + + matrix.makeRotationFromQuaternion( q ); + + return this.setFromRotationMatrix( matrix, order, update ); + + }; + + }(), + + setFromVector3: function ( v, order ) { + + return this.set( v.x, v.y, v.z, order || this._order ); + + }, + + reorder: function () { + + // WARNING: this discards revolution information -bhouston + + var q = new Quaternion(); + + return function reorder( newOrder ) { + + q.setFromEuler( this ); + + return this.setFromQuaternion( q, newOrder ); + + }; + + }(), + + equals: function ( euler ) { + + return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); + + }, + + fromArray: function ( array ) { + + this._x = array[ 0 ]; + this._y = array[ 1 ]; + this._z = array[ 2 ]; + if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; + + this.onChangeCallback(); + + return this; + + }, + + toArray: function ( array, offset ) { + + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; + + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._order; + + return array; + + }, + + toVector3: function ( optionalResult ) { + + if ( optionalResult ) { + + return optionalResult.set( this._x, this._y, this._z ); + + } else { + + return new Vector3( this._x, this._y, this._z ); + + } + + }, + + onChange: function ( callback ) { + + this.onChangeCallback = callback; + + return this; + + }, + + onChangeCallback: function () {} + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function Layers() { + + this.mask = 1; + +} + +Layers.prototype = { + + constructor: Layers, + + set: function ( channel ) { + + this.mask = 1 << channel; + + }, + + enable: function ( channel ) { + + this.mask |= 1 << channel; + + }, + + toggle: function ( channel ) { + + this.mask ^= 1 << channel; + + }, + + disable: function ( channel ) { + + this.mask &= ~ ( 1 << channel ); + + }, + + test: function ( layers ) { + + return ( this.mask & layers.mask ) !== 0; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + * @author elephantatwork / www.elephantatwork.ch + */ + +var object3DId = 0; + +function Object3D() { + + Object.defineProperty( this, 'id', { value: object3DId ++ } ); + + this.uuid = _Math.generateUUID(); + + this.name = ''; + this.type = 'Object3D'; + + this.parent = null; + this.children = []; + + this.up = Object3D.DefaultUp.clone(); + + var position = new Vector3(); + var rotation = new Euler(); + var quaternion = new Quaternion(); + var scale = new Vector3( 1, 1, 1 ); + + function onRotationChange() { + + quaternion.setFromEuler( rotation, false ); + + } + + function onQuaternionChange() { + + rotation.setFromQuaternion( quaternion, undefined, false ); + + } + + rotation.onChange( onRotationChange ); + quaternion.onChange( onQuaternionChange ); + + Object.defineProperties( this, { + position: { + enumerable: true, + value: position + }, + rotation: { + enumerable: true, + value: rotation + }, + quaternion: { + enumerable: true, + value: quaternion + }, + scale: { + enumerable: true, + value: scale + }, + modelViewMatrix: { + value: new Matrix4() + }, + normalMatrix: { + value: new Matrix3() + } + } ); + + this.matrix = new Matrix4(); + this.matrixWorld = new Matrix4(); + + this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate; + this.matrixWorldNeedsUpdate = false; + + this.layers = new Layers(); + this.visible = true; + + this.castShadow = false; + this.receiveShadow = false; + + this.frustumCulled = true; + this.renderOrder = 0; + + this.userData = {}; + + this.onBeforeRender = function () {}; + this.onAfterRender = function () {}; + +} + +Object3D.DefaultUp = new Vector3( 0, 1, 0 ); +Object3D.DefaultMatrixAutoUpdate = true; + +Object3D.prototype = { + + constructor: Object3D, + + isObject3D: true, + + applyMatrix: function ( matrix ) { + + this.matrix.multiplyMatrices( matrix, this.matrix ); + + this.matrix.decompose( this.position, this.quaternion, this.scale ); + + }, + + setRotationFromAxisAngle: function ( axis, angle ) { + + // assumes axis is normalized + + this.quaternion.setFromAxisAngle( axis, angle ); + + }, + + setRotationFromEuler: function ( euler ) { + + this.quaternion.setFromEuler( euler, true ); + + }, + + setRotationFromMatrix: function ( m ) { + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + this.quaternion.setFromRotationMatrix( m ); + + }, + + setRotationFromQuaternion: function ( q ) { + + // assumes q is normalized + + this.quaternion.copy( q ); + + }, + + rotateOnAxis: function () { + + // rotate object on axis in object space + // axis is assumed to be normalized + + var q1 = new Quaternion(); + + return function rotateOnAxis( axis, angle ) { + + q1.setFromAxisAngle( axis, angle ); + + this.quaternion.multiply( q1 ); + + return this; + + }; + + }(), + + rotateX: function () { + + var v1 = new Vector3( 1, 0, 0 ); + + return function rotateX( angle ) { + + return this.rotateOnAxis( v1, angle ); + + }; + + }(), + + rotateY: function () { + + var v1 = new Vector3( 0, 1, 0 ); + + return function rotateY( angle ) { + + return this.rotateOnAxis( v1, angle ); + + }; + + }(), + + rotateZ: function () { + + var v1 = new Vector3( 0, 0, 1 ); + + return function rotateZ( angle ) { + + return this.rotateOnAxis( v1, angle ); + + }; + + }(), + + translateOnAxis: function () { + + // translate object by distance along axis in object space + // axis is assumed to be normalized + + var v1 = new Vector3(); + + return function translateOnAxis( axis, distance ) { + + v1.copy( axis ).applyQuaternion( this.quaternion ); + + this.position.add( v1.multiplyScalar( distance ) ); + + return this; + + }; + + }(), + + translateX: function () { + + var v1 = new Vector3( 1, 0, 0 ); + + return function translateX( distance ) { + + return this.translateOnAxis( v1, distance ); + + }; + + }(), + + translateY: function () { + + var v1 = new Vector3( 0, 1, 0 ); + + return function translateY( distance ) { + + return this.translateOnAxis( v1, distance ); + + }; + + }(), + + translateZ: function () { + + var v1 = new Vector3( 0, 0, 1 ); + + return function translateZ( distance ) { + + return this.translateOnAxis( v1, distance ); + + }; + + }(), + + localToWorld: function ( vector ) { + + return vector.applyMatrix4( this.matrixWorld ); + + }, + + worldToLocal: function () { + + var m1 = new Matrix4(); + + return function worldToLocal( vector ) { + + return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) ); + + }; + + }(), + + lookAt: function () { + + // This routine does not support objects with rotated and/or translated parent(s) + + var m1 = new Matrix4(); + + return function lookAt( vector ) { + + m1.lookAt( vector, this.position, this.up ); + + this.quaternion.setFromRotationMatrix( m1 ); + + }; + + }(), + + add: function ( object ) { + + if ( arguments.length > 1 ) { + + for ( var i = 0; i < arguments.length; i ++ ) { + + this.add( arguments[ i ] ); + + } + + return this; + + } + + if ( object === this ) { + + console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object ); + return this; + + } + + if ( ( object && object.isObject3D ) ) { + + if ( object.parent !== null ) { + + object.parent.remove( object ); + + } + + object.parent = this; + object.dispatchEvent( { type: 'added' } ); + + this.children.push( object ); + + } else { + + console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object ); + + } + + return this; + + }, + + remove: function ( object ) { + + if ( arguments.length > 1 ) { + + for ( var i = 0; i < arguments.length; i ++ ) { + + this.remove( arguments[ i ] ); + + } + + } + + var index = this.children.indexOf( object ); + + if ( index !== - 1 ) { + + object.parent = null; + + object.dispatchEvent( { type: 'removed' } ); + + this.children.splice( index, 1 ); + + } + + }, + + getObjectById: function ( id ) { + + return this.getObjectByProperty( 'id', id ); + + }, + + getObjectByName: function ( name ) { + + return this.getObjectByProperty( 'name', name ); + + }, + + getObjectByProperty: function ( name, value ) { + + if ( this[ name ] === value ) return this; + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + var child = this.children[ i ]; + var object = child.getObjectByProperty( name, value ); + + if ( object !== undefined ) { + + return object; + + } + + } + + return undefined; + + }, + + getWorldPosition: function ( optionalTarget ) { + + var result = optionalTarget || new Vector3(); + + this.updateMatrixWorld( true ); + + return result.setFromMatrixPosition( this.matrixWorld ); + + }, + + getWorldQuaternion: function () { + + var position = new Vector3(); + var scale = new Vector3(); + + return function getWorldQuaternion( optionalTarget ) { + + var result = optionalTarget || new Quaternion(); + + this.updateMatrixWorld( true ); + + this.matrixWorld.decompose( position, result, scale ); + + return result; + + }; + + }(), + + getWorldRotation: function () { + + var quaternion = new Quaternion(); + + return function getWorldRotation( optionalTarget ) { + + var result = optionalTarget || new Euler(); + + this.getWorldQuaternion( quaternion ); + + return result.setFromQuaternion( quaternion, this.rotation.order, false ); + + }; + + }(), + + getWorldScale: function () { + + var position = new Vector3(); + var quaternion = new Quaternion(); + + return function getWorldScale( optionalTarget ) { + + var result = optionalTarget || new Vector3(); + + this.updateMatrixWorld( true ); + + this.matrixWorld.decompose( position, quaternion, result ); + + return result; + + }; + + }(), + + getWorldDirection: function () { + + var quaternion = new Quaternion(); + + return function getWorldDirection( optionalTarget ) { + + var result = optionalTarget || new Vector3(); + + this.getWorldQuaternion( quaternion ); + + return result.set( 0, 0, 1 ).applyQuaternion( quaternion ); + + }; + + }(), + + raycast: function () {}, + + traverse: function ( callback ) { + + callback( this ); + + var children = this.children; + + for ( var i = 0, l = children.length; i < l; i ++ ) { + + children[ i ].traverse( callback ); + + } + + }, + + traverseVisible: function ( callback ) { + + if ( this.visible === false ) return; + + callback( this ); + + var children = this.children; + + for ( var i = 0, l = children.length; i < l; i ++ ) { + + children[ i ].traverseVisible( callback ); + + } + + }, + + traverseAncestors: function ( callback ) { + + var parent = this.parent; + + if ( parent !== null ) { + + callback( parent ); + + parent.traverseAncestors( callback ); + + } + + }, + + updateMatrix: function () { + + this.matrix.compose( this.position, this.quaternion, this.scale ); + + this.matrixWorldNeedsUpdate = true; + + }, + + updateMatrixWorld: function ( force ) { + + if ( this.matrixAutoUpdate === true ) this.updateMatrix(); + + if ( this.matrixWorldNeedsUpdate === true || force === true ) { + + if ( this.parent === null ) { + + this.matrixWorld.copy( this.matrix ); + + } else { + + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + + } + + this.matrixWorldNeedsUpdate = false; + + force = true; + + } + + // update children + + var children = this.children; + + for ( var i = 0, l = children.length; i < l; i ++ ) { + + children[ i ].updateMatrixWorld( force ); + + } + + }, + + toJSON: function ( meta ) { + + // meta is '' when called from JSON.stringify + var isRootObject = ( meta === undefined || meta === '' ); + + var output = {}; + + // meta is a hash used to collect geometries, materials. + // not providing it implies that this is the root object + // being serialized. + if ( isRootObject ) { + + // initialize meta obj + meta = { + geometries: {}, + materials: {}, + textures: {}, + images: {} + }; + + output.metadata = { + version: 4.4, + type: 'Object', + generator: 'Object3D.toJSON' + }; + + } + + // standard Object3D serialization + + var object = {}; + + object.uuid = this.uuid; + object.type = this.type; + + if ( this.name !== '' ) object.name = this.name; + if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData; + if ( this.castShadow === true ) object.castShadow = true; + if ( this.receiveShadow === true ) object.receiveShadow = true; + if ( this.visible === false ) object.visible = false; + + object.matrix = this.matrix.toArray(); + + // + + if ( this.geometry !== undefined ) { + + if ( meta.geometries[ this.geometry.uuid ] === undefined ) { + + meta.geometries[ this.geometry.uuid ] = this.geometry.toJSON( meta ); + + } + + object.geometry = this.geometry.uuid; + + } + + if ( this.material !== undefined ) { + + if ( meta.materials[ this.material.uuid ] === undefined ) { + + meta.materials[ this.material.uuid ] = this.material.toJSON( meta ); + + } + + object.material = this.material.uuid; + + } + + // + + if ( this.children.length > 0 ) { + + object.children = []; + + for ( var i = 0; i < this.children.length; i ++ ) { + + object.children.push( this.children[ i ].toJSON( meta ).object ); + + } + + } + + if ( isRootObject ) { + + var geometries = extractFromCache( meta.geometries ); + var materials = extractFromCache( meta.materials ); + var textures = extractFromCache( meta.textures ); + var images = extractFromCache( meta.images ); + + if ( geometries.length > 0 ) output.geometries = geometries; + if ( materials.length > 0 ) output.materials = materials; + if ( textures.length > 0 ) output.textures = textures; + if ( images.length > 0 ) output.images = images; + + } + + output.object = object; + + return output; + + // extract data from the cache hash + // remove metadata on each item + // and return as array + function extractFromCache( cache ) { + + var values = []; + for ( var key in cache ) { + + var data = cache[ key ]; + delete data.metadata; + values.push( data ); + + } + return values; + + } + + }, + + clone: function ( recursive ) { + + return new this.constructor().copy( this, recursive ); + + }, + + copy: function ( source, recursive ) { + + if ( recursive === undefined ) recursive = true; + + this.name = source.name; + + this.up.copy( source.up ); + + this.position.copy( source.position ); + this.quaternion.copy( source.quaternion ); + this.scale.copy( source.scale ); + + this.matrix.copy( source.matrix ); + this.matrixWorld.copy( source.matrixWorld ); + + this.matrixAutoUpdate = source.matrixAutoUpdate; + this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; + + this.layers.mask = source.layers.mask; + this.visible = source.visible; + + this.castShadow = source.castShadow; + this.receiveShadow = source.receiveShadow; + + this.frustumCulled = source.frustumCulled; + this.renderOrder = source.renderOrder; + + this.userData = JSON.parse( JSON.stringify( source.userData ) ); + + if ( recursive === true ) { + + for ( var i = 0; i < source.children.length; i ++ ) { + + var child = source.children[ i ]; + this.add( child.clone() ); + + } + + } + + return this; + + } + +}; + +Object.assign( Object3D.prototype, EventDispatcher.prototype ); + +/** + * @author bhouston / http://clara.io + */ + +function Line3( start, end ) { + + this.start = ( start !== undefined ) ? start : new Vector3(); + this.end = ( end !== undefined ) ? end : new Vector3(); + +} + +Line3.prototype = { + + constructor: Line3, + + set: function ( start, end ) { + + this.start.copy( start ); + this.end.copy( end ); + + return this; + + }, + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + copy: function ( line ) { + + this.start.copy( line.start ); + this.end.copy( line.end ); + + return this; + + }, + + getCenter: function ( optionalTarget ) { + + var result = optionalTarget || new Vector3(); + return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); + + }, + + delta: function ( optionalTarget ) { + + var result = optionalTarget || new Vector3(); + return result.subVectors( this.end, this.start ); + + }, + + distanceSq: function () { + + return this.start.distanceToSquared( this.end ); + + }, + + distance: function () { + + return this.start.distanceTo( this.end ); + + }, + + at: function ( t, optionalTarget ) { + + var result = optionalTarget || new Vector3(); + + return this.delta( result ).multiplyScalar( t ).add( this.start ); + + }, + + closestPointToPointParameter: function () { + + var startP = new Vector3(); + var startEnd = new Vector3(); + + return function closestPointToPointParameter( point, clampToLine ) { + + startP.subVectors( point, this.start ); + startEnd.subVectors( this.end, this.start ); + + var startEnd2 = startEnd.dot( startEnd ); + var startEnd_startP = startEnd.dot( startP ); + + var t = startEnd_startP / startEnd2; + + if ( clampToLine ) { + + t = _Math.clamp( t, 0, 1 ); + + } + + return t; + + }; + + }(), + + closestPointToPoint: function ( point, clampToLine, optionalTarget ) { + + var t = this.closestPointToPointParameter( point, clampToLine ); + + var result = optionalTarget || new Vector3(); + + return this.delta( result ).multiplyScalar( t ).add( this.start ); + + }, + + applyMatrix4: function ( matrix ) { + + this.start.applyMatrix4( matrix ); + this.end.applyMatrix4( matrix ); + + return this; + + }, + + equals: function ( line ) { + + return line.start.equals( this.start ) && line.end.equals( this.end ); + + } + +}; + +/** + * @author bhouston / http://clara.io + * @author mrdoob / http://mrdoob.com/ + */ + +function Triangle( a, b, c ) { + + this.a = ( a !== undefined ) ? a : new Vector3(); + this.b = ( b !== undefined ) ? b : new Vector3(); + this.c = ( c !== undefined ) ? c : new Vector3(); + +} + +Triangle.normal = function () { + + var v0 = new Vector3(); + + return function normal( a, b, c, optionalTarget ) { + + var result = optionalTarget || new Vector3(); + + result.subVectors( c, b ); + v0.subVectors( a, b ); + result.cross( v0 ); + + var resultLengthSq = result.lengthSq(); + if ( resultLengthSq > 0 ) { + + return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) ); + + } + + return result.set( 0, 0, 0 ); + + }; + +}(); + +// static/instance method to calculate barycentric coordinates +// based on: http://www.blackpawn.com/texts/pointinpoly/default.html +Triangle.barycoordFromPoint = function () { + + var v0 = new Vector3(); + var v1 = new Vector3(); + var v2 = new Vector3(); + + return function barycoordFromPoint( point, a, b, c, optionalTarget ) { + + v0.subVectors( c, a ); + v1.subVectors( b, a ); + v2.subVectors( point, a ); + + var dot00 = v0.dot( v0 ); + var dot01 = v0.dot( v1 ); + var dot02 = v0.dot( v2 ); + var dot11 = v1.dot( v1 ); + var dot12 = v1.dot( v2 ); + + var denom = ( dot00 * dot11 - dot01 * dot01 ); + + var result = optionalTarget || new Vector3(); + + // collinear or singular triangle + if ( denom === 0 ) { + + // arbitrary location outside of triangle? + // not sure if this is the best idea, maybe should be returning undefined + return result.set( - 2, - 1, - 1 ); + + } + + var invDenom = 1 / denom; + var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; + var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; + + // barycentric coordinates must always sum to 1 + return result.set( 1 - u - v, v, u ); + + }; + +}(); + +Triangle.containsPoint = function () { + + var v1 = new Vector3(); + + return function containsPoint( point, a, b, c ) { + + var result = Triangle.barycoordFromPoint( point, a, b, c, v1 ); + + return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 ); + + }; + +}(); + +Triangle.prototype = { + + constructor: Triangle, + + set: function ( a, b, c ) { + + this.a.copy( a ); + this.b.copy( b ); + this.c.copy( c ); + + return this; + + }, + + setFromPointsAndIndices: function ( points, i0, i1, i2 ) { + + this.a.copy( points[ i0 ] ); + this.b.copy( points[ i1 ] ); + this.c.copy( points[ i2 ] ); + + return this; + + }, + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + copy: function ( triangle ) { + + this.a.copy( triangle.a ); + this.b.copy( triangle.b ); + this.c.copy( triangle.c ); + + return this; + + }, + + area: function () { + + var v0 = new Vector3(); + var v1 = new Vector3(); + + return function area() { + + v0.subVectors( this.c, this.b ); + v1.subVectors( this.a, this.b ); + + return v0.cross( v1 ).length() * 0.5; + + }; + + }(), + + midpoint: function ( optionalTarget ) { + + var result = optionalTarget || new Vector3(); + return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); + + }, + + normal: function ( optionalTarget ) { + + return Triangle.normal( this.a, this.b, this.c, optionalTarget ); + + }, + + plane: function ( optionalTarget ) { + + var result = optionalTarget || new Plane(); + + return result.setFromCoplanarPoints( this.a, this.b, this.c ); + + }, + + barycoordFromPoint: function ( point, optionalTarget ) { + + return Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget ); + + }, + + containsPoint: function ( point ) { + + return Triangle.containsPoint( point, this.a, this.b, this.c ); + + }, + + closestPointToPoint: function () { + + var plane, edgeList, projectedPoint, closestPoint; + + return function closestPointToPoint( point, optionalTarget ) { + + if ( plane === undefined ) { + + plane = new Plane(); + edgeList = [ new Line3(), new Line3(), new Line3() ]; + projectedPoint = new Vector3(); + closestPoint = new Vector3(); + + } + + var result = optionalTarget || new Vector3(); + var minDistance = Infinity; + + // project the point onto the plane of the triangle + + plane.setFromCoplanarPoints( this.a, this.b, this.c ); + plane.projectPoint( point, projectedPoint ); + + // check if the projection lies within the triangle + + if( this.containsPoint( projectedPoint ) === true ) { + + // if so, this is the closest point + + result.copy( projectedPoint ); + + } else { + + // if not, the point falls outside the triangle. the result is the closest point to the triangle's edges or vertices + + edgeList[ 0 ].set( this.a, this.b ); + edgeList[ 1 ].set( this.b, this.c ); + edgeList[ 2 ].set( this.c, this.a ); + + for( var i = 0; i < edgeList.length; i ++ ) { + + edgeList[ i ].closestPointToPoint( projectedPoint, true, closestPoint ); + + var distance = projectedPoint.distanceToSquared( closestPoint ); + + if( distance < minDistance ) { + + minDistance = distance; + + result.copy( closestPoint ); + + } + + } + + } + + return result; + + }; + + }(), + + equals: function ( triangle ) { + + return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +function Face3( a, b, c, normal, color, materialIndex ) { + + this.a = a; + this.b = b; + this.c = c; + + this.normal = (normal && normal.isVector3) ? normal : new Vector3(); + this.vertexNormals = Array.isArray( normal ) ? normal : []; + + this.color = (color && color.isColor) ? color : new Color(); + this.vertexColors = Array.isArray( color ) ? color : []; + + this.materialIndex = materialIndex !== undefined ? materialIndex : 0; + +} + +Face3.prototype = { + + constructor: Face3, + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + copy: function ( source ) { + + this.a = source.a; + this.b = source.b; + this.c = source.c; + + this.normal.copy( source.normal ); + this.color.copy( source.color ); + + this.materialIndex = source.materialIndex; + + for ( var i = 0, il = source.vertexNormals.length; i < il; i ++ ) { + + this.vertexNormals[ i ] = source.vertexNormals[ i ].clone(); + + } + + for ( var i = 0, il = source.vertexColors.length; i < il; i ++ ) { + + this.vertexColors[ i ] = source.vertexColors[ i ].clone(); + + } + + return this; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * map: new THREE.Texture( ), + * + * lightMap: new THREE.Texture( ), + * lightMapIntensity: + * + * aoMap: new THREE.Texture( ), + * aoMapIntensity: + * + * specularMap: new THREE.Texture( ), + * + * alphaMap: new THREE.Texture( ), + * + * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), + * combine: THREE.Multiply, + * reflectivity: , + * refractionRatio: , + * + * shading: THREE.SmoothShading, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: , + * + * skinning: , + * morphTargets: + * } + */ + +function MeshBasicMaterial( parameters ) { + + Material.call( this ); + + this.type = 'MeshBasicMaterial'; + + this.color = new Color( 0xffffff ); // emissive + + this.map = null; + + this.lightMap = null; + this.lightMapIntensity = 1.0; + + this.aoMap = null; + this.aoMapIntensity = 1.0; + + this.specularMap = null; + + this.alphaMap = null; + + this.envMap = null; + this.combine = MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.skinning = false; + this.morphTargets = false; + + this.lights = false; + + this.setValues( parameters ); + +} + +MeshBasicMaterial.prototype = Object.create( Material.prototype ); +MeshBasicMaterial.prototype.constructor = MeshBasicMaterial; + +MeshBasicMaterial.prototype.isMeshBasicMaterial = true; + +MeshBasicMaterial.prototype.copy = function ( source ) { + + Material.prototype.copy.call( this, source ); + + this.color.copy( source.color ); + + this.map = source.map; + + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; + + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; + + this.specularMap = source.specularMap; + + this.alphaMap = source.alphaMap; + + this.envMap = source.envMap; + this.combine = source.combine; + this.reflectivity = source.reflectivity; + this.refractionRatio = source.refractionRatio; + + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; + + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + + return this; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function BufferAttribute( array, itemSize, normalized ) { + + if ( Array.isArray( array ) ) { + + throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); + + } + + this.uuid = _Math.generateUUID(); + + this.array = array; + this.itemSize = itemSize; + this.count = array !== undefined ? array.length / itemSize : 0; + this.normalized = normalized === true; + + this.dynamic = false; + this.updateRange = { offset: 0, count: - 1 }; + + this.onUploadCallback = function () {}; + + this.version = 0; + +} + +BufferAttribute.prototype = { + + constructor: BufferAttribute, + + isBufferAttribute: true, + + set needsUpdate( value ) { + + if ( value === true ) this.version ++; + + }, + + setArray: function ( array ) { + + if ( Array.isArray( array ) ) { + + throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); + + } + + this.count = array !== undefined ? array.length / this.itemSize : 0; + this.array = array; + + }, + + setDynamic: function ( value ) { + + this.dynamic = value; + + return this; + + }, + + copy: function ( source ) { + + this.array = new source.array.constructor( source.array ); + this.itemSize = source.itemSize; + this.count = source.count; + this.normalized = source.normalized; + + this.dynamic = source.dynamic; + + return this; + + }, + + copyAt: function ( index1, attribute, index2 ) { + + index1 *= this.itemSize; + index2 *= attribute.itemSize; + + for ( var i = 0, l = this.itemSize; i < l; i ++ ) { + + this.array[ index1 + i ] = attribute.array[ index2 + i ]; + + } + + return this; + + }, + + copyArray: function ( array ) { + + this.array.set( array ); + + return this; + + }, + + copyColorsArray: function ( colors ) { + + var array = this.array, offset = 0; + + for ( var i = 0, l = colors.length; i < l; i ++ ) { + + var color = colors[ i ]; + + if ( color === undefined ) { + + console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i ); + color = new Color(); + + } + + array[ offset ++ ] = color.r; + array[ offset ++ ] = color.g; + array[ offset ++ ] = color.b; + + } + + return this; + + }, + + copyIndicesArray: function ( indices ) { + + var array = this.array, offset = 0; + + for ( var i = 0, l = indices.length; i < l; i ++ ) { + + var index = indices[ i ]; + + array[ offset ++ ] = index.a; + array[ offset ++ ] = index.b; + array[ offset ++ ] = index.c; + + } + + return this; + + }, + + copyVector2sArray: function ( vectors ) { + + var array = this.array, offset = 0; + + for ( var i = 0, l = vectors.length; i < l; i ++ ) { + + var vector = vectors[ i ]; + + if ( vector === undefined ) { + + console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i ); + vector = new Vector2(); + + } + + array[ offset ++ ] = vector.x; + array[ offset ++ ] = vector.y; + + } + + return this; + + }, + + copyVector3sArray: function ( vectors ) { + + var array = this.array, offset = 0; + + for ( var i = 0, l = vectors.length; i < l; i ++ ) { + + var vector = vectors[ i ]; + + if ( vector === undefined ) { + + console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i ); + vector = new Vector3(); + + } + + array[ offset ++ ] = vector.x; + array[ offset ++ ] = vector.y; + array[ offset ++ ] = vector.z; + + } + + return this; + + }, + + copyVector4sArray: function ( vectors ) { + + var array = this.array, offset = 0; + + for ( var i = 0, l = vectors.length; i < l; i ++ ) { + + var vector = vectors[ i ]; + + if ( vector === undefined ) { + + console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i ); + vector = new Vector4(); + + } + + array[ offset ++ ] = vector.x; + array[ offset ++ ] = vector.y; + array[ offset ++ ] = vector.z; + array[ offset ++ ] = vector.w; + + } + + return this; + + }, + + set: function ( value, offset ) { + + if ( offset === undefined ) offset = 0; + + this.array.set( value, offset ); + + return this; + + }, + + getX: function ( index ) { + + return this.array[ index * this.itemSize ]; + + }, + + setX: function ( index, x ) { + + this.array[ index * this.itemSize ] = x; + + return this; + + }, + + getY: function ( index ) { + + return this.array[ index * this.itemSize + 1 ]; + + }, + + setY: function ( index, y ) { + + this.array[ index * this.itemSize + 1 ] = y; + + return this; + + }, + + getZ: function ( index ) { + + return this.array[ index * this.itemSize + 2 ]; + + }, + + setZ: function ( index, z ) { + + this.array[ index * this.itemSize + 2 ] = z; + + return this; + + }, + + getW: function ( index ) { + + return this.array[ index * this.itemSize + 3 ]; + + }, + + setW: function ( index, w ) { + + this.array[ index * this.itemSize + 3 ] = w; + + return this; + + }, + + setXY: function ( index, x, y ) { + + index *= this.itemSize; + + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; + + return this; + + }, + + setXYZ: function ( index, x, y, z ) { + + index *= this.itemSize; + + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; + + return this; + + }, + + setXYZW: function ( index, x, y, z, w ) { + + index *= this.itemSize; + + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; + this.array[ index + 3 ] = w; + + return this; + + }, + + onUpload: function ( callback ) { + + this.onUploadCallback = callback; + + return this; + + }, + + clone: function () { + + return new this.constructor( this.array, this.itemSize ).copy( this ); + + } + +}; + +// + +function Int8BufferAttribute( array, itemSize ) { + + BufferAttribute.call( this, new Int8Array( array ), itemSize ); + +} + +Int8BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Int8BufferAttribute.prototype.constructor = Int8BufferAttribute; + + +function Uint8BufferAttribute( array, itemSize ) { + + BufferAttribute.call( this, new Uint8Array( array ), itemSize ); + +} + +Uint8BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Uint8BufferAttribute.prototype.constructor = Uint8BufferAttribute; + + +function Uint8ClampedBufferAttribute( array, itemSize ) { + + BufferAttribute.call( this, new Uint8ClampedArray( array ), itemSize ); + +} + +Uint8ClampedBufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Uint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute; + + +function Int16BufferAttribute( array, itemSize ) { + + BufferAttribute.call( this, new Int16Array( array ), itemSize ); + +} + +Int16BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Int16BufferAttribute.prototype.constructor = Int16BufferAttribute; + + +function Uint16BufferAttribute( array, itemSize ) { + + BufferAttribute.call( this, new Uint16Array( array ), itemSize ); + +} + +Uint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute; + + +function Int32BufferAttribute( array, itemSize ) { + + BufferAttribute.call( this, new Int32Array( array ), itemSize ); + +} + +Int32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Int32BufferAttribute.prototype.constructor = Int32BufferAttribute; + + +function Uint32BufferAttribute( array, itemSize ) { + + BufferAttribute.call( this, new Uint32Array( array ), itemSize ); + +} + +Uint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute; + + +function Float32BufferAttribute( array, itemSize ) { + + BufferAttribute.call( this, new Float32Array( array ), itemSize ); + +} + +Float32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Float32BufferAttribute.prototype.constructor = Float32BufferAttribute; + + +function Float64BufferAttribute( array, itemSize ) { + + BufferAttribute.call( this, new Float64Array( array ), itemSize ); + +} + +Float64BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Float64BufferAttribute.prototype.constructor = Float64BufferAttribute; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function DirectGeometry() { + + this.indices = []; + this.vertices = []; + this.normals = []; + this.colors = []; + this.uvs = []; + this.uvs2 = []; + + this.groups = []; + + this.morphTargets = {}; + + this.skinWeights = []; + this.skinIndices = []; + + // this.lineDistances = []; + + this.boundingBox = null; + this.boundingSphere = null; + + // update flags + + this.verticesNeedUpdate = false; + this.normalsNeedUpdate = false; + this.colorsNeedUpdate = false; + this.uvsNeedUpdate = false; + this.groupsNeedUpdate = false; + +} + +Object.assign( DirectGeometry.prototype, { + + computeGroups: function ( geometry ) { + + var group; + var groups = []; + var materialIndex = undefined; + + var faces = geometry.faces; + + for ( var i = 0; i < faces.length; i ++ ) { + + var face = faces[ i ]; + + // materials + + if ( face.materialIndex !== materialIndex ) { + + materialIndex = face.materialIndex; + + if ( group !== undefined ) { + + group.count = ( i * 3 ) - group.start; + groups.push( group ); + + } + + group = { + start: i * 3, + materialIndex: materialIndex + }; + + } + + } + + if ( group !== undefined ) { + + group.count = ( i * 3 ) - group.start; + groups.push( group ); + + } + + this.groups = groups; + + }, + + fromGeometry: function ( geometry ) { + + var faces = geometry.faces; + var vertices = geometry.vertices; + var faceVertexUvs = geometry.faceVertexUvs; + + var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0; + var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0; + + // morphs + + var morphTargets = geometry.morphTargets; + var morphTargetsLength = morphTargets.length; + + var morphTargetsPosition; + + if ( morphTargetsLength > 0 ) { + + morphTargetsPosition = []; + + for ( var i = 0; i < morphTargetsLength; i ++ ) { + + morphTargetsPosition[ i ] = []; + + } + + this.morphTargets.position = morphTargetsPosition; + + } + + var morphNormals = geometry.morphNormals; + var morphNormalsLength = morphNormals.length; + + var morphTargetsNormal; + + if ( morphNormalsLength > 0 ) { + + morphTargetsNormal = []; + + for ( var i = 0; i < morphNormalsLength; i ++ ) { + + morphTargetsNormal[ i ] = []; + + } + + this.morphTargets.normal = morphTargetsNormal; + + } + + // skins + + var skinIndices = geometry.skinIndices; + var skinWeights = geometry.skinWeights; + + var hasSkinIndices = skinIndices.length === vertices.length; + var hasSkinWeights = skinWeights.length === vertices.length; + + // + + for ( var i = 0; i < faces.length; i ++ ) { + + var face = faces[ i ]; + + this.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] ); + + var vertexNormals = face.vertexNormals; + + if ( vertexNormals.length === 3 ) { + + this.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] ); + + } else { + + var normal = face.normal; + + this.normals.push( normal, normal, normal ); + + } + + var vertexColors = face.vertexColors; + + if ( vertexColors.length === 3 ) { + + this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] ); + + } else { + + var color = face.color; + + this.colors.push( color, color, color ); + + } + + if ( hasFaceVertexUv === true ) { + + var vertexUvs = faceVertexUvs[ 0 ][ i ]; + + if ( vertexUvs !== undefined ) { + + this.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] ); + + } else { + + console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i ); + + this.uvs.push( new Vector2(), new Vector2(), new Vector2() ); + + } + + } + + if ( hasFaceVertexUv2 === true ) { + + var vertexUvs = faceVertexUvs[ 1 ][ i ]; + + if ( vertexUvs !== undefined ) { + + this.uvs2.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] ); + + } else { + + console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i ); + + this.uvs2.push( new Vector2(), new Vector2(), new Vector2() ); + + } + + } + + // morphs + + for ( var j = 0; j < morphTargetsLength; j ++ ) { + + var morphTarget = morphTargets[ j ].vertices; + + morphTargetsPosition[ j ].push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] ); + + } + + for ( var j = 0; j < morphNormalsLength; j ++ ) { + + var morphNormal = morphNormals[ j ].vertexNormals[ i ]; + + morphTargetsNormal[ j ].push( morphNormal.a, morphNormal.b, morphNormal.c ); + + } + + // skins + + if ( hasSkinIndices ) { + + this.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] ); + + } + + if ( hasSkinWeights ) { + + this.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] ); + + } + + } + + this.computeGroups( geometry ); + + this.verticesNeedUpdate = geometry.verticesNeedUpdate; + this.normalsNeedUpdate = geometry.normalsNeedUpdate; + this.colorsNeedUpdate = geometry.colorsNeedUpdate; + this.uvsNeedUpdate = geometry.uvsNeedUpdate; + this.groupsNeedUpdate = geometry.groupsNeedUpdate; + + return this; + + } + +} ); + +// http://stackoverflow.com/questions/1669190/javascript-min-max-array-values/13440842#13440842 + +function arrayMax( array ) { + + var length = array.length, max = - Infinity; + + while ( length -- ) { + + if ( array[ length ] > max ) { + + max = array[ length ]; + + } + + } + + return max; + +} + +/** + * @author mrdoob / http://mrdoob.com/ + * @author kile / http://kile.stravaganza.org/ + * @author alteredq / http://alteredqualia.com/ + * @author mikael emtinger / http://gomo.se/ + * @author zz85 / http://www.lab4games.net/zz85/blog + * @author bhouston / http://clara.io + */ + +var count = 0; +function GeometryIdCount() { return count++; } + +function Geometry() { + + Object.defineProperty( this, 'id', { value: GeometryIdCount() } ); + + this.uuid = _Math.generateUUID(); + + this.name = ''; + this.type = 'Geometry'; + + this.vertices = []; + this.colors = []; + this.faces = []; + this.faceVertexUvs = [[]]; + + this.morphTargets = []; + this.morphNormals = []; + + this.skinWeights = []; + this.skinIndices = []; + + this.lineDistances = []; + + this.boundingBox = null; + this.boundingSphere = null; + + // update flags + + this.elementsNeedUpdate = false; + this.verticesNeedUpdate = false; + this.uvsNeedUpdate = false; + this.normalsNeedUpdate = false; + this.colorsNeedUpdate = false; + this.lineDistancesNeedUpdate = false; + this.groupsNeedUpdate = false; + +} + +Geometry.prototype = { + + constructor: Geometry, + + isGeometry: true, + + applyMatrix: function ( matrix ) { + + var normalMatrix = new Matrix3().getNormalMatrix( matrix ); + + for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { + + var vertex = this.vertices[ i ]; + vertex.applyMatrix4( matrix ); + + } + + for ( var i = 0, il = this.faces.length; i < il; i ++ ) { + + var face = this.faces[ i ]; + face.normal.applyMatrix3( normalMatrix ).normalize(); + + for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { + + face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize(); + + } + + } + + if ( this.boundingBox !== null ) { + + this.computeBoundingBox(); + + } + + if ( this.boundingSphere !== null ) { + + this.computeBoundingSphere(); + + } + + this.verticesNeedUpdate = true; + this.normalsNeedUpdate = true; + + return this; + + }, + + rotateX: function () { + + // rotate geometry around world x-axis + + var m1; + + return function rotateX( angle ) { + + if ( m1 === undefined ) m1 = new Matrix4(); + + m1.makeRotationX( angle ); + + this.applyMatrix( m1 ); + + return this; + + }; + + }(), + + rotateY: function () { + + // rotate geometry around world y-axis + + var m1; + + return function rotateY( angle ) { + + if ( m1 === undefined ) m1 = new Matrix4(); + + m1.makeRotationY( angle ); + + this.applyMatrix( m1 ); + + return this; + + }; + + }(), + + rotateZ: function () { + + // rotate geometry around world z-axis + + var m1; + + return function rotateZ( angle ) { + + if ( m1 === undefined ) m1 = new Matrix4(); + + m1.makeRotationZ( angle ); + + this.applyMatrix( m1 ); + + return this; + + }; + + }(), + + translate: function () { + + // translate geometry + + var m1; + + return function translate( x, y, z ) { + + if ( m1 === undefined ) m1 = new Matrix4(); + + m1.makeTranslation( x, y, z ); + + this.applyMatrix( m1 ); + + return this; + + }; + + }(), + + scale: function () { + + // scale geometry + + var m1; + + return function scale( x, y, z ) { + + if ( m1 === undefined ) m1 = new Matrix4(); + + m1.makeScale( x, y, z ); + + this.applyMatrix( m1 ); + + return this; + + }; + + }(), + + lookAt: function () { + + var obj; + + return function lookAt( vector ) { + + if ( obj === undefined ) obj = new Object3D(); + + obj.lookAt( vector ); + + obj.updateMatrix(); + + this.applyMatrix( obj.matrix ); + + }; + + }(), + + fromBufferGeometry: function ( geometry ) { + + var scope = this; + + var indices = geometry.index !== null ? geometry.index.array : undefined; + var attributes = geometry.attributes; + + var positions = attributes.position.array; + var normals = attributes.normal !== undefined ? attributes.normal.array : undefined; + var colors = attributes.color !== undefined ? attributes.color.array : undefined; + var uvs = attributes.uv !== undefined ? attributes.uv.array : undefined; + var uvs2 = attributes.uv2 !== undefined ? attributes.uv2.array : undefined; + + if ( uvs2 !== undefined ) this.faceVertexUvs[ 1 ] = []; + + var tempNormals = []; + var tempUVs = []; + var tempUVs2 = []; + + for ( var i = 0, j = 0; i < positions.length; i += 3, j += 2 ) { + + scope.vertices.push( new Vector3( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ) ); + + if ( normals !== undefined ) { + + tempNormals.push( new Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) ); + + } + + if ( colors !== undefined ) { + + scope.colors.push( new Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) ); + + } + + if ( uvs !== undefined ) { + + tempUVs.push( new Vector2( uvs[ j ], uvs[ j + 1 ] ) ); + + } + + if ( uvs2 !== undefined ) { + + tempUVs2.push( new Vector2( uvs2[ j ], uvs2[ j + 1 ] ) ); + + } + + } + + function addFace( a, b, c, materialIndex ) { + + var vertexNormals = normals !== undefined ? [ tempNormals[ a ].clone(), tempNormals[ b ].clone(), tempNormals[ c ].clone() ] : []; + var vertexColors = colors !== undefined ? [ scope.colors[ a ].clone(), scope.colors[ b ].clone(), scope.colors[ c ].clone() ] : []; + + var face = new Face3( a, b, c, vertexNormals, vertexColors, materialIndex ); + + scope.faces.push( face ); + + if ( uvs !== undefined ) { + + scope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] ); + + } + + if ( uvs2 !== undefined ) { + + scope.faceVertexUvs[ 1 ].push( [ tempUVs2[ a ].clone(), tempUVs2[ b ].clone(), tempUVs2[ c ].clone() ] ); + + } + + } + + if ( indices !== undefined ) { + + var groups = geometry.groups; + + if ( groups.length > 0 ) { + + for ( var i = 0; i < groups.length; i ++ ) { + + var group = groups[ i ]; + + var start = group.start; + var count = group.count; + + for ( var j = start, jl = start + count; j < jl; j += 3 ) { + + addFace( indices[ j ], indices[ j + 1 ], indices[ j + 2 ], group.materialIndex ); + + } + + } + + } else { + + for ( var i = 0; i < indices.length; i += 3 ) { + + addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); + + } + + } + + } else { + + for ( var i = 0; i < positions.length / 3; i += 3 ) { + + addFace( i, i + 1, i + 2 ); + + } + + } + + this.computeFaceNormals(); + + if ( geometry.boundingBox !== null ) { + + this.boundingBox = geometry.boundingBox.clone(); + + } + + if ( geometry.boundingSphere !== null ) { + + this.boundingSphere = geometry.boundingSphere.clone(); + + } + + return this; + + }, + + center: function () { + + this.computeBoundingBox(); + + var offset = this.boundingBox.getCenter().negate(); + + this.translate( offset.x, offset.y, offset.z ); + + return offset; + + }, + + normalize: function () { + + this.computeBoundingSphere(); + + var center = this.boundingSphere.center; + var radius = this.boundingSphere.radius; + + var s = radius === 0 ? 1 : 1.0 / radius; + + var matrix = new Matrix4(); + matrix.set( + s, 0, 0, - s * center.x, + 0, s, 0, - s * center.y, + 0, 0, s, - s * center.z, + 0, 0, 0, 1 + ); + + this.applyMatrix( matrix ); + + return this; + + }, + + computeFaceNormals: function () { + + var cb = new Vector3(), ab = new Vector3(); + + for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { + + var face = this.faces[ f ]; + + var vA = this.vertices[ face.a ]; + var vB = this.vertices[ face.b ]; + var vC = this.vertices[ face.c ]; + + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ); + + cb.normalize(); + + face.normal.copy( cb ); + + } + + }, + + computeVertexNormals: function ( areaWeighted ) { + + if ( areaWeighted === undefined ) areaWeighted = true; + + var v, vl, f, fl, face, vertices; + + vertices = new Array( this.vertices.length ); + + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + + vertices[ v ] = new Vector3(); + + } + + if ( areaWeighted ) { + + // vertex normals weighted by triangle areas + // http://www.iquilezles.org/www/articles/normals/normals.htm + + var vA, vB, vC; + var cb = new Vector3(), ab = new Vector3(); + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + vA = this.vertices[ face.a ]; + vB = this.vertices[ face.b ]; + vC = this.vertices[ face.c ]; + + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ); + + vertices[ face.a ].add( cb ); + vertices[ face.b ].add( cb ); + vertices[ face.c ].add( cb ); + + } + + } else { + + this.computeFaceNormals(); + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + vertices[ face.a ].add( face.normal ); + vertices[ face.b ].add( face.normal ); + vertices[ face.c ].add( face.normal ); + + } + + } + + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + + vertices[ v ].normalize(); + + } + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + var vertexNormals = face.vertexNormals; + + if ( vertexNormals.length === 3 ) { + + vertexNormals[ 0 ].copy( vertices[ face.a ] ); + vertexNormals[ 1 ].copy( vertices[ face.b ] ); + vertexNormals[ 2 ].copy( vertices[ face.c ] ); + + } else { + + vertexNormals[ 0 ] = vertices[ face.a ].clone(); + vertexNormals[ 1 ] = vertices[ face.b ].clone(); + vertexNormals[ 2 ] = vertices[ face.c ].clone(); + + } + + } + + if ( this.faces.length > 0 ) { + + this.normalsNeedUpdate = true; + + } + + }, + + computeFlatVertexNormals: function () { + + var f, fl, face; + + this.computeFaceNormals(); + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + var vertexNormals = face.vertexNormals; + + if ( vertexNormals.length === 3 ) { + + vertexNormals[ 0 ].copy( face.normal ); + vertexNormals[ 1 ].copy( face.normal ); + vertexNormals[ 2 ].copy( face.normal ); + + } else { + + vertexNormals[ 0 ] = face.normal.clone(); + vertexNormals[ 1 ] = face.normal.clone(); + vertexNormals[ 2 ] = face.normal.clone(); + + } + + } + + if ( this.faces.length > 0 ) { + + this.normalsNeedUpdate = true; + + } + + }, + + computeMorphNormals: function () { + + var i, il, f, fl, face; + + // save original normals + // - create temp variables on first access + // otherwise just copy (for faster repeated calls) + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + if ( ! face.__originalFaceNormal ) { + + face.__originalFaceNormal = face.normal.clone(); + + } else { + + face.__originalFaceNormal.copy( face.normal ); + + } + + if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = []; + + for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) { + + if ( ! face.__originalVertexNormals[ i ] ) { + + face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone(); + + } else { + + face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] ); + + } + + } + + } + + // use temp geometry to compute face and vertex normals for each morph + + var tmpGeo = new Geometry(); + tmpGeo.faces = this.faces; + + for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) { + + // create on first access + + if ( ! this.morphNormals[ i ] ) { + + this.morphNormals[ i ] = {}; + this.morphNormals[ i ].faceNormals = []; + this.morphNormals[ i ].vertexNormals = []; + + var dstNormalsFace = this.morphNormals[ i ].faceNormals; + var dstNormalsVertex = this.morphNormals[ i ].vertexNormals; + + var faceNormal, vertexNormals; + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + faceNormal = new Vector3(); + vertexNormals = { a: new Vector3(), b: new Vector3(), c: new Vector3() }; + + dstNormalsFace.push( faceNormal ); + dstNormalsVertex.push( vertexNormals ); + + } + + } + + var morphNormals = this.morphNormals[ i ]; + + // set vertices to morph target + + tmpGeo.vertices = this.morphTargets[ i ].vertices; + + // compute morph normals + + tmpGeo.computeFaceNormals(); + tmpGeo.computeVertexNormals(); + + // store morph normals + + var faceNormal, vertexNormals; + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + faceNormal = morphNormals.faceNormals[ f ]; + vertexNormals = morphNormals.vertexNormals[ f ]; + + faceNormal.copy( face.normal ); + + vertexNormals.a.copy( face.vertexNormals[ 0 ] ); + vertexNormals.b.copy( face.vertexNormals[ 1 ] ); + vertexNormals.c.copy( face.vertexNormals[ 2 ] ); + + } + + } + + // restore original normals + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + face.normal = face.__originalFaceNormal; + face.vertexNormals = face.__originalVertexNormals; + + } + + }, + + computeLineDistances: function () { + + var d = 0; + var vertices = this.vertices; + + for ( var i = 0, il = vertices.length; i < il; i ++ ) { + + if ( i > 0 ) { + + d += vertices[ i ].distanceTo( vertices[ i - 1 ] ); + + } + + this.lineDistances[ i ] = d; + + } + + }, + + computeBoundingBox: function () { + + if ( this.boundingBox === null ) { + + this.boundingBox = new Box3(); + + } + + this.boundingBox.setFromPoints( this.vertices ); + + }, + + computeBoundingSphere: function () { + + if ( this.boundingSphere === null ) { + + this.boundingSphere = new Sphere(); + + } + + this.boundingSphere.setFromPoints( this.vertices ); + + }, + + merge: function ( geometry, matrix, materialIndexOffset ) { + + if ( ( geometry && geometry.isGeometry ) === false ) { + + console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry ); + return; + + } + + var normalMatrix, + vertexOffset = this.vertices.length, + vertices1 = this.vertices, + vertices2 = geometry.vertices, + faces1 = this.faces, + faces2 = geometry.faces, + uvs1 = this.faceVertexUvs[ 0 ], + uvs2 = geometry.faceVertexUvs[ 0 ], + colors1 = this.colors, + colors2 = geometry.colors; + + if ( materialIndexOffset === undefined ) materialIndexOffset = 0; + + if ( matrix !== undefined ) { + + normalMatrix = new Matrix3().getNormalMatrix( matrix ); + + } + + // vertices + + for ( var i = 0, il = vertices2.length; i < il; i ++ ) { + + var vertex = vertices2[ i ]; + + var vertexCopy = vertex.clone(); + + if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix ); + + vertices1.push( vertexCopy ); + + } + + // colors + + for ( var i = 0, il = colors2.length; i < il; i ++ ) { + + colors1.push( colors2[ i ].clone() ); + + } + + // faces + + for ( i = 0, il = faces2.length; i < il; i ++ ) { + + var face = faces2[ i ], faceCopy, normal, color, + faceVertexNormals = face.vertexNormals, + faceVertexColors = face.vertexColors; + + faceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); + faceCopy.normal.copy( face.normal ); + + if ( normalMatrix !== undefined ) { + + faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); + + } + + for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { + + normal = faceVertexNormals[ j ].clone(); + + if ( normalMatrix !== undefined ) { + + normal.applyMatrix3( normalMatrix ).normalize(); + + } + + faceCopy.vertexNormals.push( normal ); + + } + + faceCopy.color.copy( face.color ); + + for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) { + + color = faceVertexColors[ j ]; + faceCopy.vertexColors.push( color.clone() ); + + } + + faceCopy.materialIndex = face.materialIndex + materialIndexOffset; + + faces1.push( faceCopy ); + + } + + // uvs + + for ( i = 0, il = uvs2.length; i < il; i ++ ) { + + var uv = uvs2[ i ], uvCopy = []; + + if ( uv === undefined ) { + + continue; + + } + + for ( var j = 0, jl = uv.length; j < jl; j ++ ) { + + uvCopy.push( uv[ j ].clone() ); + + } + + uvs1.push( uvCopy ); + + } + + }, + + mergeMesh: function ( mesh ) { + + if ( ( mesh && mesh.isMesh ) === false ) { + + console.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh ); + return; + + } + + mesh.matrixAutoUpdate && mesh.updateMatrix(); + + this.merge( mesh.geometry, mesh.matrix ); + + }, + + /* + * Checks for duplicate vertices with hashmap. + * Duplicated vertices are removed + * and faces' vertices are updated. + */ + + mergeVertices: function () { + + var verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique) + var unique = [], changes = []; + + var v, key; + var precisionPoints = 4; // number of decimal points, e.g. 4 for epsilon of 0.0001 + var precision = Math.pow( 10, precisionPoints ); + var i, il, face; + var indices, j, jl; + + for ( i = 0, il = this.vertices.length; i < il; i ++ ) { + + v = this.vertices[ i ]; + key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision ); + + if ( verticesMap[ key ] === undefined ) { + + verticesMap[ key ] = i; + unique.push( this.vertices[ i ] ); + changes[ i ] = unique.length - 1; + + } else { + + //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); + changes[ i ] = changes[ verticesMap[ key ] ]; + + } + + } + + + // if faces are completely degenerate after merging vertices, we + // have to remove them from the geometry. + var faceIndicesToRemove = []; + + for ( i = 0, il = this.faces.length; i < il; i ++ ) { + + face = this.faces[ i ]; + + face.a = changes[ face.a ]; + face.b = changes[ face.b ]; + face.c = changes[ face.c ]; + + indices = [ face.a, face.b, face.c ]; + + // if any duplicate vertices are found in a Face3 + // we have to remove the face as nothing can be saved + for ( var n = 0; n < 3; n ++ ) { + + if ( indices[ n ] === indices[ ( n + 1 ) % 3 ] ) { + + faceIndicesToRemove.push( i ); + break; + + } + + } + + } + + for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) { + + var idx = faceIndicesToRemove[ i ]; + + this.faces.splice( idx, 1 ); + + for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { + + this.faceVertexUvs[ j ].splice( idx, 1 ); + + } + + } + + // Use unique set of vertices + + var diff = this.vertices.length - unique.length; + this.vertices = unique; + return diff; + + }, + + sortFacesByMaterialIndex: function () { + + var faces = this.faces; + var length = faces.length; + + // tag faces + + for ( var i = 0; i < length; i ++ ) { + + faces[ i ]._id = i; + + } + + // sort faces + + function materialIndexSort( a, b ) { + + return a.materialIndex - b.materialIndex; + + } + + faces.sort( materialIndexSort ); + + // sort uvs + + var uvs1 = this.faceVertexUvs[ 0 ]; + var uvs2 = this.faceVertexUvs[ 1 ]; + + var newUvs1, newUvs2; + + if ( uvs1 && uvs1.length === length ) newUvs1 = []; + if ( uvs2 && uvs2.length === length ) newUvs2 = []; + + for ( var i = 0; i < length; i ++ ) { + + var id = faces[ i ]._id; + + if ( newUvs1 ) newUvs1.push( uvs1[ id ] ); + if ( newUvs2 ) newUvs2.push( uvs2[ id ] ); + + } + + if ( newUvs1 ) this.faceVertexUvs[ 0 ] = newUvs1; + if ( newUvs2 ) this.faceVertexUvs[ 1 ] = newUvs2; + + }, + + toJSON: function () { + + var data = { + metadata: { + version: 4.4, + type: 'Geometry', + generator: 'Geometry.toJSON' + } + }; + + // standard Geometry serialization + + data.uuid = this.uuid; + data.type = this.type; + if ( this.name !== '' ) data.name = this.name; + + if ( this.parameters !== undefined ) { + + var parameters = this.parameters; + + for ( var key in parameters ) { + + if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; + + } + + return data; + + } + + var vertices = []; + + for ( var i = 0; i < this.vertices.length; i ++ ) { + + var vertex = this.vertices[ i ]; + vertices.push( vertex.x, vertex.y, vertex.z ); + + } + + var faces = []; + var normals = []; + var normalsHash = {}; + var colors = []; + var colorsHash = {}; + var uvs = []; + var uvsHash = {}; + + for ( var i = 0; i < this.faces.length; i ++ ) { + + var face = this.faces[ i ]; + + var hasMaterial = true; + var hasFaceUv = false; // deprecated + var hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i ] !== undefined; + var hasFaceNormal = face.normal.length() > 0; + var hasFaceVertexNormal = face.vertexNormals.length > 0; + var hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1; + var hasFaceVertexColor = face.vertexColors.length > 0; + + var faceType = 0; + + faceType = setBit( faceType, 0, 0 ); // isQuad + faceType = setBit( faceType, 1, hasMaterial ); + faceType = setBit( faceType, 2, hasFaceUv ); + faceType = setBit( faceType, 3, hasFaceVertexUv ); + faceType = setBit( faceType, 4, hasFaceNormal ); + faceType = setBit( faceType, 5, hasFaceVertexNormal ); + faceType = setBit( faceType, 6, hasFaceColor ); + faceType = setBit( faceType, 7, hasFaceVertexColor ); + + faces.push( faceType ); + faces.push( face.a, face.b, face.c ); + faces.push( face.materialIndex ); + + if ( hasFaceVertexUv ) { + + var faceVertexUvs = this.faceVertexUvs[ 0 ][ i ]; + + faces.push( + getUvIndex( faceVertexUvs[ 0 ] ), + getUvIndex( faceVertexUvs[ 1 ] ), + getUvIndex( faceVertexUvs[ 2 ] ) + ); + + } + + if ( hasFaceNormal ) { + + faces.push( getNormalIndex( face.normal ) ); + + } + + if ( hasFaceVertexNormal ) { + + var vertexNormals = face.vertexNormals; + + faces.push( + getNormalIndex( vertexNormals[ 0 ] ), + getNormalIndex( vertexNormals[ 1 ] ), + getNormalIndex( vertexNormals[ 2 ] ) + ); + + } + + if ( hasFaceColor ) { + + faces.push( getColorIndex( face.color ) ); + + } + + if ( hasFaceVertexColor ) { + + var vertexColors = face.vertexColors; + + faces.push( + getColorIndex( vertexColors[ 0 ] ), + getColorIndex( vertexColors[ 1 ] ), + getColorIndex( vertexColors[ 2 ] ) + ); + + } + + } + + function setBit( value, position, enabled ) { + + return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position ) ); + + } + + function getNormalIndex( normal ) { + + var hash = normal.x.toString() + normal.y.toString() + normal.z.toString(); + + if ( normalsHash[ hash ] !== undefined ) { + + return normalsHash[ hash ]; + + } + + normalsHash[ hash ] = normals.length / 3; + normals.push( normal.x, normal.y, normal.z ); + + return normalsHash[ hash ]; + + } + + function getColorIndex( color ) { + + var hash = color.r.toString() + color.g.toString() + color.b.toString(); + + if ( colorsHash[ hash ] !== undefined ) { + + return colorsHash[ hash ]; + + } + + colorsHash[ hash ] = colors.length; + colors.push( color.getHex() ); + + return colorsHash[ hash ]; + + } + + function getUvIndex( uv ) { + + var hash = uv.x.toString() + uv.y.toString(); + + if ( uvsHash[ hash ] !== undefined ) { + + return uvsHash[ hash ]; + + } + + uvsHash[ hash ] = uvs.length / 2; + uvs.push( uv.x, uv.y ); + + return uvsHash[ hash ]; + + } + + data.data = {}; + + data.data.vertices = vertices; + data.data.normals = normals; + if ( colors.length > 0 ) data.data.colors = colors; + if ( uvs.length > 0 ) data.data.uvs = [ uvs ]; // temporal backward compatibility + data.data.faces = faces; + + return data; + + }, + + clone: function () { + + /* + // Handle primitives + + var parameters = this.parameters; + + if ( parameters !== undefined ) { + + var values = []; + + for ( var key in parameters ) { + + values.push( parameters[ key ] ); + + } + + var geometry = Object.create( this.constructor.prototype ); + this.constructor.apply( geometry, values ); + return geometry; + + } + + return new this.constructor().copy( this ); + */ + + return new Geometry().copy( this ); + + }, + + copy: function ( source ) { + + var i, il, j, jl, k, kl; + + // reset + + this.vertices = []; + this.colors = []; + this.faces = []; + this.faceVertexUvs = [[]]; + this.morphTargets = []; + this.morphNormals = []; + this.skinWeights = []; + this.skinIndices = []; + this.lineDistances = []; + this.boundingBox = null; + this.boundingSphere = null; + + // name + + this.name = source.name; + + // vertices + + var vertices = source.vertices; + + for ( i = 0, il = vertices.length; i < il; i ++ ) { + + this.vertices.push( vertices[ i ].clone() ); + + } + + // colors + + var colors = source.colors; + + for ( i = 0, il = colors.length; i < il; i ++ ) { + + this.colors.push( colors[ i ].clone() ); + + } + + // faces + + var faces = source.faces; + + for ( i = 0, il = faces.length; i < il; i ++ ) { + + this.faces.push( faces[ i ].clone() ); + + } + + // face vertex uvs + + for ( i = 0, il = source.faceVertexUvs.length; i < il; i ++ ) { + + var faceVertexUvs = source.faceVertexUvs[ i ]; + + if ( this.faceVertexUvs[ i ] === undefined ) { + + this.faceVertexUvs[ i ] = []; + + } + + for ( j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) { + + var uvs = faceVertexUvs[ j ], uvsCopy = []; + + for ( k = 0, kl = uvs.length; k < kl; k ++ ) { + + var uv = uvs[ k ]; + + uvsCopy.push( uv.clone() ); + + } + + this.faceVertexUvs[ i ].push( uvsCopy ); + + } + + } + + // morph targets + + var morphTargets = source.morphTargets; + + for ( i = 0, il = morphTargets.length; i < il; i ++ ) { + + var morphTarget = {}; + morphTarget.name = morphTargets[ i ].name; + + // vertices + + if ( morphTargets[ i ].vertices !== undefined ) { + + morphTarget.vertices = []; + + for ( j = 0, jl = morphTargets[ i ].vertices.length; j < jl; j ++ ) { + + morphTarget.vertices.push( morphTargets[ i ].vertices[ j ].clone() ); + + } + + } + + // normals + + if ( morphTargets[ i ].normals !== undefined ) { + + morphTarget.normals = []; + + for ( j = 0, jl = morphTargets[ i ].normals.length; j < jl; j ++ ) { + + morphTarget.normals.push( morphTargets[ i ].normals[ j ].clone() ); + + } + + } + + this.morphTargets.push( morphTarget ); + + } + + // morph normals + + var morphNormals = source.morphNormals; + + for ( i = 0, il = morphNormals.length; i < il; i ++ ) { + + var morphNormal = {}; + + // vertex normals + + if ( morphNormals[ i ].vertexNormals !== undefined ) { + + morphNormal.vertexNormals = []; + + for ( j = 0, jl = morphNormals[ i ].vertexNormals.length; j < jl; j ++ ) { + + var srcVertexNormal = morphNormals[ i ].vertexNormals[ j ]; + var destVertexNormal = {}; + + destVertexNormal.a = srcVertexNormal.a.clone(); + destVertexNormal.b = srcVertexNormal.b.clone(); + destVertexNormal.c = srcVertexNormal.c.clone(); + + morphNormal.vertexNormals.push( destVertexNormal ); + + } + + } + + // face normals + + if ( morphNormals[ i ].faceNormals !== undefined ) { + + morphNormal.faceNormals = []; + + for ( j = 0, jl = morphNormals[ i ].faceNormals.length; j < jl; j ++ ) { + + morphNormal.faceNormals.push( morphNormals[ i ].faceNormals[ j ].clone() ); + + } + + } + + this.morphNormals.push( morphNormal ); + + } + + // skin weights + + var skinWeights = source.skinWeights; + + for ( i = 0, il = skinWeights.length; i < il; i ++ ) { + + this.skinWeights.push( skinWeights[ i ].clone() ); + + } + + // skin indices + + var skinIndices = source.skinIndices; + + for ( i = 0, il = skinIndices.length; i < il; i ++ ) { + + this.skinIndices.push( skinIndices[ i ].clone() ); + + } + + // line distances + + var lineDistances = source.lineDistances; + + for ( i = 0, il = lineDistances.length; i < il; i ++ ) { + + this.lineDistances.push( lineDistances[ i ] ); + + } + + // bounding box + + var boundingBox = source.boundingBox; + + if ( boundingBox !== null ) { + + this.boundingBox = boundingBox.clone(); + + } + + // bounding sphere + + var boundingSphere = source.boundingSphere; + + if ( boundingSphere !== null ) { + + this.boundingSphere = boundingSphere.clone(); + + } + + // update flags + + this.elementsNeedUpdate = source.elementsNeedUpdate; + this.verticesNeedUpdate = source.verticesNeedUpdate; + this.uvsNeedUpdate = source.uvsNeedUpdate; + this.normalsNeedUpdate = source.normalsNeedUpdate; + this.colorsNeedUpdate = source.colorsNeedUpdate; + this.lineDistancesNeedUpdate = source.lineDistancesNeedUpdate; + this.groupsNeedUpdate = source.groupsNeedUpdate; + + return this; + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +}; + +Object.assign( Geometry.prototype, EventDispatcher.prototype ); + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ + +function BufferGeometry() { + + Object.defineProperty( this, 'id', { value: GeometryIdCount() } ); + + this.uuid = _Math.generateUUID(); + + this.name = ''; + this.type = 'BufferGeometry'; + + this.index = null; + this.attributes = {}; + + this.morphAttributes = {}; + + this.groups = []; + + this.boundingBox = null; + this.boundingSphere = null; + + this.drawRange = { start: 0, count: Infinity }; + +} + +BufferGeometry.prototype = { + + constructor: BufferGeometry, + + isBufferGeometry: true, + + getIndex: function () { + + return this.index; + + }, + + setIndex: function ( index ) { + + if ( Array.isArray( index ) ) { + + this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 ); + + } else { + + this.index = index; + + } + + }, + + addAttribute: function ( name, attribute ) { + + if ( ( attribute && attribute.isBufferAttribute ) === false && ( attribute && attribute.isInterleavedBufferAttribute ) === false ) { + + console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' ); + + this.addAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) ); + + return; + + } + + if ( name === 'index' ) { + + console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' ); + this.setIndex( attribute ); + + return; + + } + + this.attributes[ name ] = attribute; + + return this; + + }, + + getAttribute: function ( name ) { + + return this.attributes[ name ]; + + }, + + removeAttribute: function ( name ) { + + delete this.attributes[ name ]; + + return this; + + }, + + addGroup: function ( start, count, materialIndex ) { + + this.groups.push( { + + start: start, + count: count, + materialIndex: materialIndex !== undefined ? materialIndex : 0 + + } ); + + }, + + clearGroups: function () { + + this.groups = []; + + }, + + setDrawRange: function ( start, count ) { + + this.drawRange.start = start; + this.drawRange.count = count; + + }, + + applyMatrix: function ( matrix ) { + + var position = this.attributes.position; + + if ( position !== undefined ) { + + matrix.applyToBufferAttribute( position ); + position.needsUpdate = true; + + } + + var normal = this.attributes.normal; + + if ( normal !== undefined ) { + + var normalMatrix = new Matrix3().getNormalMatrix( matrix ); + + normalMatrix.applyToBufferAttribute( normal ); + normal.needsUpdate = true; + + } + + if ( this.boundingBox !== null ) { + + this.computeBoundingBox(); + + } + + if ( this.boundingSphere !== null ) { + + this.computeBoundingSphere(); + + } + + return this; + + }, + + rotateX: function () { + + // rotate geometry around world x-axis + + var m1; + + return function rotateX( angle ) { + + if ( m1 === undefined ) m1 = new Matrix4(); + + m1.makeRotationX( angle ); + + this.applyMatrix( m1 ); + + return this; + + }; + + }(), + + rotateY: function () { + + // rotate geometry around world y-axis + + var m1; + + return function rotateY( angle ) { + + if ( m1 === undefined ) m1 = new Matrix4(); + + m1.makeRotationY( angle ); + + this.applyMatrix( m1 ); + + return this; + + }; + + }(), + + rotateZ: function () { + + // rotate geometry around world z-axis + + var m1; + + return function rotateZ( angle ) { + + if ( m1 === undefined ) m1 = new Matrix4(); + + m1.makeRotationZ( angle ); + + this.applyMatrix( m1 ); + + return this; + + }; + + }(), + + translate: function () { + + // translate geometry + + var m1; + + return function translate( x, y, z ) { + + if ( m1 === undefined ) m1 = new Matrix4(); + + m1.makeTranslation( x, y, z ); + + this.applyMatrix( m1 ); + + return this; + + }; + + }(), + + scale: function () { + + // scale geometry + + var m1; + + return function scale( x, y, z ) { + + if ( m1 === undefined ) m1 = new Matrix4(); + + m1.makeScale( x, y, z ); + + this.applyMatrix( m1 ); + + return this; + + }; + + }(), + + lookAt: function () { + + var obj; + + return function lookAt( vector ) { + + if ( obj === undefined ) obj = new Object3D(); + + obj.lookAt( vector ); + + obj.updateMatrix(); + + this.applyMatrix( obj.matrix ); + + }; + + }(), + + center: function () { + + this.computeBoundingBox(); + + var offset = this.boundingBox.getCenter().negate(); + + this.translate( offset.x, offset.y, offset.z ); + + return offset; + + }, + + setFromObject: function ( object ) { + + // console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this ); + + var geometry = object.geometry; + + if ( object.isPoints || object.isLine ) { + + var positions = new Float32BufferAttribute( geometry.vertices.length * 3, 3 ); + var colors = new Float32BufferAttribute( geometry.colors.length * 3, 3 ); + + this.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) ); + this.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) ); + + if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) { + + var lineDistances = new Float32BufferAttribute( geometry.lineDistances.length, 1 ); + + this.addAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) ); + + } + + if ( geometry.boundingSphere !== null ) { + + this.boundingSphere = geometry.boundingSphere.clone(); + + } + + if ( geometry.boundingBox !== null ) { + + this.boundingBox = geometry.boundingBox.clone(); + + } + + } else if ( object.isMesh ) { + + if ( geometry && geometry.isGeometry ) { + + this.fromGeometry( geometry ); + + } + + } + + return this; + + }, + + updateFromObject: function ( object ) { + + var geometry = object.geometry; + + if ( object.isMesh ) { + + var direct = geometry.__directGeometry; + + if ( geometry.elementsNeedUpdate === true ) { + + direct = undefined; + geometry.elementsNeedUpdate = false; + + } + + if ( direct === undefined ) { + + return this.fromGeometry( geometry ); + + } + + direct.verticesNeedUpdate = geometry.verticesNeedUpdate; + direct.normalsNeedUpdate = geometry.normalsNeedUpdate; + direct.colorsNeedUpdate = geometry.colorsNeedUpdate; + direct.uvsNeedUpdate = geometry.uvsNeedUpdate; + direct.groupsNeedUpdate = geometry.groupsNeedUpdate; + + geometry.verticesNeedUpdate = false; + geometry.normalsNeedUpdate = false; + geometry.colorsNeedUpdate = false; + geometry.uvsNeedUpdate = false; + geometry.groupsNeedUpdate = false; + + geometry = direct; + + } + + var attribute; + + if ( geometry.verticesNeedUpdate === true ) { + + attribute = this.attributes.position; + + if ( attribute !== undefined ) { + + attribute.copyVector3sArray( geometry.vertices ); + attribute.needsUpdate = true; + + } + + geometry.verticesNeedUpdate = false; + + } + + if ( geometry.normalsNeedUpdate === true ) { + + attribute = this.attributes.normal; + + if ( attribute !== undefined ) { + + attribute.copyVector3sArray( geometry.normals ); + attribute.needsUpdate = true; + + } + + geometry.normalsNeedUpdate = false; + + } + + if ( geometry.colorsNeedUpdate === true ) { + + attribute = this.attributes.color; + + if ( attribute !== undefined ) { + + attribute.copyColorsArray( geometry.colors ); + attribute.needsUpdate = true; + + } + + geometry.colorsNeedUpdate = false; + + } + + if ( geometry.uvsNeedUpdate ) { + + attribute = this.attributes.uv; + + if ( attribute !== undefined ) { + + attribute.copyVector2sArray( geometry.uvs ); + attribute.needsUpdate = true; + + } + + geometry.uvsNeedUpdate = false; + + } + + if ( geometry.lineDistancesNeedUpdate ) { + + attribute = this.attributes.lineDistance; + + if ( attribute !== undefined ) { + + attribute.copyArray( geometry.lineDistances ); + attribute.needsUpdate = true; + + } + + geometry.lineDistancesNeedUpdate = false; + + } + + if ( geometry.groupsNeedUpdate ) { + + geometry.computeGroups( object.geometry ); + this.groups = geometry.groups; + + geometry.groupsNeedUpdate = false; + + } + + return this; + + }, + + fromGeometry: function ( geometry ) { + + geometry.__directGeometry = new DirectGeometry().fromGeometry( geometry ); + + return this.fromDirectGeometry( geometry.__directGeometry ); + + }, + + fromDirectGeometry: function ( geometry ) { + + var positions = new Float32Array( geometry.vertices.length * 3 ); + this.addAttribute( 'position', new BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) ); + + if ( geometry.normals.length > 0 ) { + + var normals = new Float32Array( geometry.normals.length * 3 ); + this.addAttribute( 'normal', new BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) ); + + } + + if ( geometry.colors.length > 0 ) { + + var colors = new Float32Array( geometry.colors.length * 3 ); + this.addAttribute( 'color', new BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) ); + + } + + if ( geometry.uvs.length > 0 ) { + + var uvs = new Float32Array( geometry.uvs.length * 2 ); + this.addAttribute( 'uv', new BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) ); + + } + + if ( geometry.uvs2.length > 0 ) { + + var uvs2 = new Float32Array( geometry.uvs2.length * 2 ); + this.addAttribute( 'uv2', new BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) ); + + } + + if ( geometry.indices.length > 0 ) { + + var TypeArray = arrayMax( geometry.indices ) > 65535 ? Uint32Array : Uint16Array; + var indices = new TypeArray( geometry.indices.length * 3 ); + this.setIndex( new BufferAttribute( indices, 1 ).copyIndicesArray( geometry.indices ) ); + + } + + // groups + + this.groups = geometry.groups; + + // morphs + + for ( var name in geometry.morphTargets ) { + + var array = []; + var morphTargets = geometry.morphTargets[ name ]; + + for ( var i = 0, l = morphTargets.length; i < l; i ++ ) { + + var morphTarget = morphTargets[ i ]; + + var attribute = new Float32BufferAttribute( morphTarget.length * 3, 3 ); + + array.push( attribute.copyVector3sArray( morphTarget ) ); + + } + + this.morphAttributes[ name ] = array; + + } + + // skinning + + if ( geometry.skinIndices.length > 0 ) { + + var skinIndices = new Float32BufferAttribute( geometry.skinIndices.length * 4, 4 ); + this.addAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) ); + + } + + if ( geometry.skinWeights.length > 0 ) { + + var skinWeights = new Float32BufferAttribute( geometry.skinWeights.length * 4, 4 ); + this.addAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) ); + + } + + // + + if ( geometry.boundingSphere !== null ) { + + this.boundingSphere = geometry.boundingSphere.clone(); + + } + + if ( geometry.boundingBox !== null ) { + + this.boundingBox = geometry.boundingBox.clone(); + + } + + return this; + + }, + + computeBoundingBox: function () { + + if ( this.boundingBox === null ) { + + this.boundingBox = new Box3(); + + } + + var position = this.attributes.position; + + if ( position !== undefined ) { + + this.boundingBox.setFromBufferAttribute( position ); + + } else { + + this.boundingBox.makeEmpty(); + + } + + if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { + + console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); + + } + + }, + + computeBoundingSphere: function () { + + var box = new Box3(); + var vector = new Vector3(); + + return function computeBoundingSphere() { + + if ( this.boundingSphere === null ) { + + this.boundingSphere = new Sphere(); + + } + + var position = this.attributes.position; + + if ( position ) { + + var center = this.boundingSphere.center; + + box.setFromBufferAttribute( position ); + box.getCenter( center ); + + // hoping to find a boundingSphere with a radius smaller than the + // boundingSphere of the boundingBox: sqrt(3) smaller in the best case + + var maxRadiusSq = 0; + + for ( var i = 0, il = position.count; i < il; i ++ ) { + + vector.x = position.getX( i ); + vector.y = position.getY( i ); + vector.z = position.getZ( i ); + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); + + } + + this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); + + if ( isNaN( this.boundingSphere.radius ) ) { + + console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); + + } + + } + + }; + + }(), + + computeFaceNormals: function () { + + // backwards compatibility + + }, + + computeVertexNormals: function () { + + var index = this.index; + var attributes = this.attributes; + var groups = this.groups; + + if ( attributes.position ) { + + var positions = attributes.position.array; + + if ( attributes.normal === undefined ) { + + this.addAttribute( 'normal', new BufferAttribute( new Float32Array( positions.length ), 3 ) ); + + } else { + + // reset existing normals to zero + + var array = attributes.normal.array; + + for ( var i = 0, il = array.length; i < il; i ++ ) { + + array[ i ] = 0; + + } + + } + + var normals = attributes.normal.array; + + var vA, vB, vC; + var pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); + var cb = new Vector3(), ab = new Vector3(); + + // indexed elements + + if ( index ) { + + var indices = index.array; + + if ( groups.length === 0 ) { + + this.addGroup( 0, indices.length ); + + } + + for ( var j = 0, jl = groups.length; j < jl; ++ j ) { + + var group = groups[ j ]; + + var start = group.start; + var count = group.count; + + for ( var i = start, il = start + count; i < il; i += 3 ) { + + vA = indices[ i + 0 ] * 3; + vB = indices[ i + 1 ] * 3; + vC = indices[ i + 2 ] * 3; + + pA.fromArray( positions, vA ); + pB.fromArray( positions, vB ); + pC.fromArray( positions, vC ); + + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); + + normals[ vA ] += cb.x; + normals[ vA + 1 ] += cb.y; + normals[ vA + 2 ] += cb.z; + + normals[ vB ] += cb.x; + normals[ vB + 1 ] += cb.y; + normals[ vB + 2 ] += cb.z; + + normals[ vC ] += cb.x; + normals[ vC + 1 ] += cb.y; + normals[ vC + 2 ] += cb.z; + + } + + } + + } else { + + // non-indexed elements (unconnected triangle soup) + + for ( var i = 0, il = positions.length; i < il; i += 9 ) { + + pA.fromArray( positions, i ); + pB.fromArray( positions, i + 3 ); + pC.fromArray( positions, i + 6 ); + + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); + + normals[ i ] = cb.x; + normals[ i + 1 ] = cb.y; + normals[ i + 2 ] = cb.z; + + normals[ i + 3 ] = cb.x; + normals[ i + 4 ] = cb.y; + normals[ i + 5 ] = cb.z; + + normals[ i + 6 ] = cb.x; + normals[ i + 7 ] = cb.y; + normals[ i + 8 ] = cb.z; + + } + + } + + this.normalizeNormals(); + + attributes.normal.needsUpdate = true; + + } + + }, + + merge: function ( geometry, offset ) { + + if ( ( geometry && geometry.isBufferGeometry ) === false ) { + + console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry ); + return; + + } + + if ( offset === undefined ) offset = 0; + + var attributes = this.attributes; + + for ( var key in attributes ) { + + if ( geometry.attributes[ key ] === undefined ) continue; + + var attribute1 = attributes[ key ]; + var attributeArray1 = attribute1.array; + + var attribute2 = geometry.attributes[ key ]; + var attributeArray2 = attribute2.array; + + var attributeSize = attribute2.itemSize; + + for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) { + + attributeArray1[ j ] = attributeArray2[ i ]; + + } + + } + + return this; + + }, + + normalizeNormals: function () { + + var normals = this.attributes.normal.array; + + var x, y, z, n; + + for ( var i = 0, il = normals.length; i < il; i += 3 ) { + + x = normals[ i ]; + y = normals[ i + 1 ]; + z = normals[ i + 2 ]; + + n = 1.0 / Math.sqrt( x * x + y * y + z * z ); + + normals[ i ] *= n; + normals[ i + 1 ] *= n; + normals[ i + 2 ] *= n; + + } + + }, + + toNonIndexed: function () { + + if ( this.index === null ) { + + console.warn( 'THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.' ); + return this; + + } + + var geometry2 = new BufferGeometry(); + + var indices = this.index.array; + var attributes = this.attributes; + + for ( var name in attributes ) { + + var attribute = attributes[ name ]; + + var array = attribute.array; + var itemSize = attribute.itemSize; + + var array2 = new array.constructor( indices.length * itemSize ); + + var index = 0, index2 = 0; + + for ( var i = 0, l = indices.length; i < l; i ++ ) { + + index = indices[ i ] * itemSize; + + for ( var j = 0; j < itemSize; j ++ ) { + + array2[ index2 ++ ] = array[ index ++ ]; + + } + + } + + geometry2.addAttribute( name, new BufferAttribute( array2, itemSize ) ); + + } + + return geometry2; + + }, + + toJSON: function () { + + var data = { + metadata: { + version: 4.4, + type: 'BufferGeometry', + generator: 'BufferGeometry.toJSON' + } + }; + + // standard BufferGeometry serialization + + data.uuid = this.uuid; + data.type = this.type; + if ( this.name !== '' ) data.name = this.name; + + if ( this.parameters !== undefined ) { + + var parameters = this.parameters; + + for ( var key in parameters ) { + + if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; + + } + + return data; + + } + + data.data = { attributes: {} }; + + var index = this.index; + + if ( index !== null ) { + + var array = Array.prototype.slice.call( index.array ); + + data.data.index = { + type: index.array.constructor.name, + array: array + }; + + } + + var attributes = this.attributes; + + for ( var key in attributes ) { + + var attribute = attributes[ key ]; + + var array = Array.prototype.slice.call( attribute.array ); + + data.data.attributes[ key ] = { + itemSize: attribute.itemSize, + type: attribute.array.constructor.name, + array: array, + normalized: attribute.normalized + }; + + } + + var groups = this.groups; + + if ( groups.length > 0 ) { + + data.data.groups = JSON.parse( JSON.stringify( groups ) ); + + } + + var boundingSphere = this.boundingSphere; + + if ( boundingSphere !== null ) { + + data.data.boundingSphere = { + center: boundingSphere.center.toArray(), + radius: boundingSphere.radius + }; + + } + + return data; + + }, + + clone: function () { + + /* + // Handle primitives + + var parameters = this.parameters; + + if ( parameters !== undefined ) { + + var values = []; + + for ( var key in parameters ) { + + values.push( parameters[ key ] ); + + } + + var geometry = Object.create( this.constructor.prototype ); + this.constructor.apply( geometry, values ); + return geometry; + + } + + return new this.constructor().copy( this ); + */ + + return new BufferGeometry().copy( this ); + + }, + + copy: function ( source ) { + + var name, i, l; + + // reset + + this.index = null; + this.attributes = {}; + this.morphAttributes = {}; + this.groups = []; + this.boundingBox = null; + this.boundingSphere = null; + + // name + + this.name = source.name; + + // index + + var index = source.index; + + if ( index !== null ) { + + this.setIndex( index.clone() ); + + } + + // attributes + + var attributes = source.attributes; + + for ( name in attributes ) { + + var attribute = attributes[ name ]; + this.addAttribute( name, attribute.clone() ); + + } + + // morph attributes + + var morphAttributes = source.morphAttributes; + + for ( name in morphAttributes ) { + + var array = []; + var morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes + + for ( i = 0, l = morphAttribute.length; i < l; i ++ ) { + + array.push( morphAttribute[ i ].clone() ); + + } + + this.morphAttributes[ name ] = array; + + } + + // groups + + var groups = source.groups; + + for ( i = 0, l = groups.length; i < l; i ++ ) { + + var group = groups[ i ]; + this.addGroup( group.start, group.count, group.materialIndex ); + + } + + // bounding box + + var boundingBox = source.boundingBox; + + if ( boundingBox !== null ) { + + this.boundingBox = boundingBox.clone(); + + } + + // bounding sphere + + var boundingSphere = source.boundingSphere; + + if ( boundingSphere !== null ) { + + this.boundingSphere = boundingSphere.clone(); + + } + + // draw range + + this.drawRange.start = source.drawRange.start; + this.drawRange.count = source.drawRange.count; + + return this; + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +}; + +BufferGeometry.MaxIndex = 65535; + +Object.assign( BufferGeometry.prototype, EventDispatcher.prototype ); + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author mikael emtinger / http://gomo.se/ + * @author jonobr1 / http://jonobr1.com/ + */ + +function Mesh( geometry, material ) { + + Object3D.call( this ); + + this.type = 'Mesh'; + + this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); + this.material = material !== undefined ? material : new MeshBasicMaterial( { color: Math.random() * 0xffffff } ); + + this.drawMode = TrianglesDrawMode; + + this.updateMorphTargets(); + +} + +Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), { + + constructor: Mesh, + + isMesh: true, + + setDrawMode: function ( value ) { + + this.drawMode = value; + + }, + + copy: function ( source ) { + + Object3D.prototype.copy.call( this, source ); + + this.drawMode = source.drawMode; + + return this; + + }, + + updateMorphTargets: function () { + + var morphTargets = this.geometry.morphTargets; + + if ( morphTargets !== undefined && morphTargets.length > 0 ) { + + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; + + for ( var m = 0, ml = morphTargets.length; m < ml; m ++ ) { + + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ morphTargets[ m ].name ] = m; + + } + + } + + }, + + raycast: ( function () { + + var inverseMatrix = new Matrix4(); + var ray = new Ray(); + var sphere = new Sphere(); + + var vA = new Vector3(); + var vB = new Vector3(); + var vC = new Vector3(); + + var tempA = new Vector3(); + var tempB = new Vector3(); + var tempC = new Vector3(); + + var uvA = new Vector2(); + var uvB = new Vector2(); + var uvC = new Vector2(); + + var barycoord = new Vector3(); + + var intersectionPoint = new Vector3(); + var intersectionPointWorld = new Vector3(); + + function uvIntersection( point, p1, p2, p3, uv1, uv2, uv3 ) { + + Triangle.barycoordFromPoint( point, p1, p2, p3, barycoord ); + + uv1.multiplyScalar( barycoord.x ); + uv2.multiplyScalar( barycoord.y ); + uv3.multiplyScalar( barycoord.z ); + + uv1.add( uv2 ).add( uv3 ); + + return uv1.clone(); + + } + + function checkIntersection( object, raycaster, ray, pA, pB, pC, point ) { + + var intersect; + var material = object.material; + + if ( material.side === BackSide ) { + + intersect = ray.intersectTriangle( pC, pB, pA, true, point ); + + } else { + + intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point ); + + } + + if ( intersect === null ) return null; + + intersectionPointWorld.copy( point ); + intersectionPointWorld.applyMatrix4( object.matrixWorld ); + + var distance = raycaster.ray.origin.distanceTo( intersectionPointWorld ); + + if ( distance < raycaster.near || distance > raycaster.far ) return null; + + return { + distance: distance, + point: intersectionPointWorld.clone(), + object: object + }; + + } + + function checkBufferGeometryIntersection( object, raycaster, ray, position, uv, a, b, c ) { + + vA.fromBufferAttribute( position, a ); + vB.fromBufferAttribute( position, b ); + vC.fromBufferAttribute( position, c ); + + var intersection = checkIntersection( object, raycaster, ray, vA, vB, vC, intersectionPoint ); + + if ( intersection ) { + + if ( uv ) { + + uvA.fromBufferAttribute( uv, a ); + uvB.fromBufferAttribute( uv, b ); + uvC.fromBufferAttribute( uv, c ); + + intersection.uv = uvIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC ); + + } + + intersection.face = new Face3( a, b, c, Triangle.normal( vA, vB, vC ) ); + intersection.faceIndex = a; + + } + + return intersection; + + } + + return function raycast( raycaster, intersects ) { + + var geometry = this.geometry; + var material = this.material; + var matrixWorld = this.matrixWorld; + + if ( material === undefined ) return; + + // Checking boundingSphere distance to ray + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( matrixWorld ); + + if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; + + // + + inverseMatrix.getInverse( matrixWorld ); + ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); + + // Check boundingBox before continuing + + if ( geometry.boundingBox !== null ) { + + if ( ray.intersectsBox( geometry.boundingBox ) === false ) return; + + } + + var intersection; + + if ( geometry.isBufferGeometry ) { + + var a, b, c; + var index = geometry.index; + var position = geometry.attributes.position; + var uv = geometry.attributes.uv; + var i, l; + + if ( index !== null ) { + + // indexed buffer geometry + + for ( i = 0, l = index.count; i < l; i += 3 ) { + + a = index.getX( i ); + b = index.getX( i + 1 ); + c = index.getX( i + 2 ); + + intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c ); + + if ( intersection ) { + + intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indices buffer semantics + intersects.push( intersection ); + + } + + } + + } else { + + // non-indexed buffer geometry + + for ( i = 0, l = position.count; i < l; i += 3 ) { + + a = i; + b = i + 1; + c = i + 2; + + intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c ); + + if ( intersection ) { + + intersection.index = a; // triangle number in positions buffer semantics + intersects.push( intersection ); + + } + + } + + } + + } else if ( geometry.isGeometry ) { + + var fvA, fvB, fvC; + var isFaceMaterial = ( material && material.isMultiMaterial ); + var materials = isFaceMaterial === true ? material.materials : null; + + var vertices = geometry.vertices; + var faces = geometry.faces; + var uvs; + + var faceVertexUvs = geometry.faceVertexUvs[ 0 ]; + if ( faceVertexUvs.length > 0 ) uvs = faceVertexUvs; + + for ( var f = 0, fl = faces.length; f < fl; f ++ ) { + + var face = faces[ f ]; + var faceMaterial = isFaceMaterial === true ? materials[ face.materialIndex ] : material; + + if ( faceMaterial === undefined ) continue; + + fvA = vertices[ face.a ]; + fvB = vertices[ face.b ]; + fvC = vertices[ face.c ]; + + if ( faceMaterial.morphTargets === true ) { + + var morphTargets = geometry.morphTargets; + var morphInfluences = this.morphTargetInfluences; + + vA.set( 0, 0, 0 ); + vB.set( 0, 0, 0 ); + vC.set( 0, 0, 0 ); + + for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { + + var influence = morphInfluences[ t ]; + + if ( influence === 0 ) continue; + + var targets = morphTargets[ t ].vertices; + + vA.addScaledVector( tempA.subVectors( targets[ face.a ], fvA ), influence ); + vB.addScaledVector( tempB.subVectors( targets[ face.b ], fvB ), influence ); + vC.addScaledVector( tempC.subVectors( targets[ face.c ], fvC ), influence ); + + } + + vA.add( fvA ); + vB.add( fvB ); + vC.add( fvC ); + + fvA = vA; + fvB = vB; + fvC = vC; + + } + + intersection = checkIntersection( this, raycaster, ray, fvA, fvB, fvC, intersectionPoint ); + + if ( intersection ) { + + if ( uvs ) { + + var uvs_f = uvs[ f ]; + uvA.copy( uvs_f[ 0 ] ); + uvB.copy( uvs_f[ 1 ] ); + uvC.copy( uvs_f[ 2 ] ); + + intersection.uv = uvIntersection( intersectionPoint, fvA, fvB, fvC, uvA, uvB, uvC ); + + } + + intersection.face = face; + intersection.faceIndex = f; + intersects.push( intersection ); + + } + + } + + } + + }; + + }() ), + + clone: function () { + + return new this.constructor( this.geometry, this.material ).copy( this ); + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as + */ + +function BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) { + + Geometry.call( this ); + + this.type = 'BoxGeometry'; + + this.parameters = { + width: width, + height: height, + depth: depth, + widthSegments: widthSegments, + heightSegments: heightSegments, + depthSegments: depthSegments + }; + + this.fromBufferGeometry( new BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) ); + this.mergeVertices(); + +} + +BoxGeometry.prototype = Object.create( Geometry.prototype ); +BoxGeometry.prototype.constructor = BoxGeometry; + +/** + * @author Mugen87 / https://github.com/Mugen87 + */ + +function BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) { + + BufferGeometry.call( this ); + + this.type = 'BoxBufferGeometry'; + + this.parameters = { + width: width, + height: height, + depth: depth, + widthSegments: widthSegments, + heightSegments: heightSegments, + depthSegments: depthSegments + }; + + var scope = this; + + // segments + + widthSegments = Math.floor( widthSegments ) || 1; + heightSegments = Math.floor( heightSegments ) || 1; + depthSegments = Math.floor( depthSegments ) || 1; + + // buffers + + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; + + // helper variables + + var numberOfVertices = 0; + var groupStart = 0; + + // build each side of the box geometry + + buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px + buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx + buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py + buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny + buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz + buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz + + // build geometry + + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + + function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) { + + var segmentWidth = width / gridX; + var segmentHeight = height / gridY; + + var widthHalf = width / 2; + var heightHalf = height / 2; + var depthHalf = depth / 2; + + var gridX1 = gridX + 1; + var gridY1 = gridY + 1; + + var vertexCounter = 0; + var groupCount = 0; + + var ix, iy; + + var vector = new Vector3(); + + // generate vertices, normals and uvs + + for ( iy = 0; iy < gridY1; iy ++ ) { + + var y = iy * segmentHeight - heightHalf; + + for ( ix = 0; ix < gridX1; ix ++ ) { + + var x = ix * segmentWidth - widthHalf; + + // set values to correct vector component + + vector[ u ] = x * udir; + vector[ v ] = y * vdir; + vector[ w ] = depthHalf; + + // now apply vector to vertex buffer + + vertices.push( vector.x, vector.y, vector.z ); + + // set values to correct vector component + + vector[ u ] = 0; + vector[ v ] = 0; + vector[ w ] = depth > 0 ? 1 : - 1; + + // now apply vector to normal buffer + + normals.push( vector.x, vector.y, vector.z ); + + // uvs + + uvs.push( ix / gridX ); + uvs.push( 1 - ( iy / gridY ) ); + + // counters + + vertexCounter += 1; + + } + + } + + // indices + + // 1. you need three indices to draw a single face + // 2. a single segment consists of two faces + // 3. so we need to generate six (2*3) indices per segment + + for ( iy = 0; iy < gridY; iy ++ ) { + + for ( ix = 0; ix < gridX; ix ++ ) { + + var a = numberOfVertices + ix + gridX1 * iy; + var b = numberOfVertices + ix + gridX1 * ( iy + 1 ); + var c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 ); + var d = numberOfVertices + ( ix + 1 ) + gridX1 * iy; + + // faces + + indices.push( a, b, d ); + indices.push( b, c, d ); + + // increase counter + + groupCount += 6; + + } + + } + + // add a group to the geometry. this will ensure multi material support + + scope.addGroup( groupStart, groupCount, materialIndex ); + + // calculate new start value for groups + + groupStart += groupCount; + + // update total number of vertices + + numberOfVertices += vertexCounter; + + } + +} + +BoxBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +BoxBufferGeometry.prototype.constructor = BoxBufferGeometry; + +/** + * @author mrdoob / http://mrdoob.com/ + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as + */ + +function PlaneGeometry( width, height, widthSegments, heightSegments ) { + + Geometry.call( this ); + + this.type = 'PlaneGeometry'; + + this.parameters = { + width: width, + height: height, + widthSegments: widthSegments, + heightSegments: heightSegments + }; + + this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) ); + +} + +PlaneGeometry.prototype = Object.create( Geometry.prototype ); +PlaneGeometry.prototype.constructor = PlaneGeometry; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author Mugen87 / https://github.com/Mugen87 + * + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as + */ + +function PlaneBufferGeometry( width, height, widthSegments, heightSegments ) { + + BufferGeometry.call( this ); + + this.type = 'PlaneBufferGeometry'; + + this.parameters = { + width: width, + height: height, + widthSegments: widthSegments, + heightSegments: heightSegments + }; + + var width_half = width / 2; + var height_half = height / 2; + + var gridX = Math.floor( widthSegments ) || 1; + var gridY = Math.floor( heightSegments ) || 1; + + var gridX1 = gridX + 1; + var gridY1 = gridY + 1; + + var segment_width = width / gridX; + var segment_height = height / gridY; + + var ix, iy; + + // buffers + + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; + + // generate vertices, normals and uvs + + for ( iy = 0; iy < gridY1; iy ++ ) { + + var y = iy * segment_height - height_half; + + for ( ix = 0; ix < gridX1; ix ++ ) { + + var x = ix * segment_width - width_half; + + vertices.push( x, - y, 0 ); + + normals.push( 0, 0, 1 ); + + uvs.push( ix / gridX ); + uvs.push( 1 - ( iy / gridY ) ); + + } + + } + + // indices + + for ( iy = 0; iy < gridY; iy ++ ) { + + for ( ix = 0; ix < gridX; ix ++ ) { + + var a = ix + gridX1 * iy; + var b = ix + gridX1 * ( iy + 1 ); + var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); + var d = ( ix + 1 ) + gridX1 * iy; + + // faces + + indices.push( a, b, d ); + indices.push( b, c, d ); + + } + + } + + // build geometry + + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + +} + +PlaneBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +PlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + * @author WestLangley / http://github.com/WestLangley +*/ + +function Camera() { + + Object3D.call( this ); + + this.type = 'Camera'; + + this.matrixWorldInverse = new Matrix4(); + this.projectionMatrix = new Matrix4(); + +} + +Camera.prototype = Object.create( Object3D.prototype ); +Camera.prototype.constructor = Camera; + +Camera.prototype.isCamera = true; + +Camera.prototype.getWorldDirection = function () { + + var quaternion = new Quaternion(); + + return function getWorldDirection( optionalTarget ) { + + var result = optionalTarget || new Vector3(); + + this.getWorldQuaternion( quaternion ); + + return result.set( 0, 0, - 1 ).applyQuaternion( quaternion ); + + }; + +}(); + +Camera.prototype.lookAt = function () { + + // This routine does not support cameras with rotated and/or translated parent(s) + + var m1 = new Matrix4(); + + return function lookAt( vector ) { + + m1.lookAt( this.position, vector, this.up ); + + this.quaternion.setFromRotationMatrix( m1 ); + + }; + +}(); + +Camera.prototype.clone = function () { + + return new this.constructor().copy( this ); + +}; + +Camera.prototype.copy = function ( source ) { + + Object3D.prototype.copy.call( this, source ); + + this.matrixWorldInverse.copy( source.matrixWorldInverse ); + this.projectionMatrix.copy( source.projectionMatrix ); + + return this; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author greggman / http://games.greggman.com/ + * @author zz85 / http://www.lab4games.net/zz85/blog + * @author tschw + */ + +function PerspectiveCamera( fov, aspect, near, far ) { + + Camera.call( this ); + + this.type = 'PerspectiveCamera'; + + this.fov = fov !== undefined ? fov : 50; + this.zoom = 1; + + this.near = near !== undefined ? near : 0.1; + this.far = far !== undefined ? far : 2000; + this.focus = 10; + + this.aspect = aspect !== undefined ? aspect : 1; + this.view = null; + + this.filmGauge = 35; // width of the film (default in millimeters) + this.filmOffset = 0; // horizontal film offset (same unit as gauge) + + this.updateProjectionMatrix(); + +} + +PerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ), { + + constructor: PerspectiveCamera, + + isPerspectiveCamera: true, + + copy: function ( source ) { + + Camera.prototype.copy.call( this, source ); + + this.fov = source.fov; + this.zoom = source.zoom; + + this.near = source.near; + this.far = source.far; + this.focus = source.focus; + + this.aspect = source.aspect; + this.view = source.view === null ? null : Object.assign( {}, source.view ); + + this.filmGauge = source.filmGauge; + this.filmOffset = source.filmOffset; + + return this; + + }, + + /** + * Sets the FOV by focal length in respect to the current .filmGauge. + * + * The default film gauge is 35, so that the focal length can be specified for + * a 35mm (full frame) camera. + * + * Values for focal length and film gauge must have the same unit. + */ + setFocalLength: function ( focalLength ) { + + // see http://www.bobatkins.com/photography/technical/field_of_view.html + var vExtentSlope = 0.5 * this.getFilmHeight() / focalLength; + + this.fov = _Math.RAD2DEG * 2 * Math.atan( vExtentSlope ); + this.updateProjectionMatrix(); + + }, + + /** + * Calculates the focal length from the current .fov and .filmGauge. + */ + getFocalLength: function () { + + var vExtentSlope = Math.tan( _Math.DEG2RAD * 0.5 * this.fov ); + + return 0.5 * this.getFilmHeight() / vExtentSlope; + + }, + + getEffectiveFOV: function () { + + return _Math.RAD2DEG * 2 * Math.atan( + Math.tan( _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom ); + + }, + + getFilmWidth: function () { + + // film not completely covered in portrait format (aspect < 1) + return this.filmGauge * Math.min( this.aspect, 1 ); + + }, + + getFilmHeight: function () { + + // film not completely covered in landscape format (aspect > 1) + return this.filmGauge / Math.max( this.aspect, 1 ); + + }, + + /** + * 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. + */ + setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) { + + this.aspect = fullWidth / fullHeight; + + this.view = { + fullWidth: fullWidth, + fullHeight: fullHeight, + offsetX: x, + offsetY: y, + width: width, + height: height + }; + + this.updateProjectionMatrix(); + + }, + + clearViewOffset: function() { + + this.view = null; + this.updateProjectionMatrix(); + + }, + + updateProjectionMatrix: function () { + + var near = this.near, + top = near * Math.tan( + _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom, + height = 2 * top, + width = this.aspect * height, + left = - 0.5 * width, + view = this.view; + + if ( view !== null ) { + + var fullWidth = view.fullWidth, + fullHeight = view.fullHeight; + + left += view.offsetX * width / fullWidth; + top -= view.offsetY * height / fullHeight; + width *= view.width / fullWidth; + height *= view.height / fullHeight; + + } + + var skew = this.filmOffset; + if ( skew !== 0 ) left += near * skew / this.getFilmWidth(); + + this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far ); + + }, + + toJSON: function ( meta ) { + + var data = Object3D.prototype.toJSON.call( this, meta ); + + data.object.fov = this.fov; + data.object.zoom = this.zoom; + + data.object.near = this.near; + data.object.far = this.far; + data.object.focus = this.focus; + + data.object.aspect = this.aspect; + + if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); + + data.object.filmGauge = this.filmGauge; + data.object.filmOffset = this.filmOffset; + + return data; + + } + +} ); + +/** + * @author alteredq / http://alteredqualia.com/ + * @author arose / http://github.com/arose + */ + +function OrthographicCamera( left, right, top, bottom, near, far ) { + + Camera.call( this ); + + this.type = 'OrthographicCamera'; + + this.zoom = 1; + this.view = null; + + this.left = left; + this.right = right; + this.top = top; + this.bottom = bottom; + + this.near = ( near !== undefined ) ? near : 0.1; + this.far = ( far !== undefined ) ? far : 2000; + + this.updateProjectionMatrix(); + +} + +OrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), { + + constructor: OrthographicCamera, + + isOrthographicCamera: true, + + copy: function ( source ) { + + Camera.prototype.copy.call( this, source ); + + this.left = source.left; + this.right = source.right; + this.top = source.top; + this.bottom = source.bottom; + this.near = source.near; + this.far = source.far; + + this.zoom = source.zoom; + this.view = source.view === null ? null : Object.assign( {}, source.view ); + + return this; + + }, + + setViewOffset: function( fullWidth, fullHeight, x, y, width, height ) { + + this.view = { + fullWidth: fullWidth, + fullHeight: fullHeight, + offsetX: x, + offsetY: y, + width: width, + height: height + }; + + this.updateProjectionMatrix(); + + }, + + clearViewOffset: function() { + + this.view = null; + this.updateProjectionMatrix(); + + }, + + updateProjectionMatrix: function () { + + var dx = ( this.right - this.left ) / ( 2 * this.zoom ); + var dy = ( this.top - this.bottom ) / ( 2 * this.zoom ); + var cx = ( this.right + this.left ) / 2; + var cy = ( this.top + this.bottom ) / 2; + + var left = cx - dx; + var right = cx + dx; + var top = cy + dy; + var bottom = cy - dy; + + if ( this.view !== null ) { + + var zoomW = this.zoom / ( this.view.width / this.view.fullWidth ); + var zoomH = this.zoom / ( this.view.height / this.view.fullHeight ); + var scaleW = ( this.right - this.left ) / this.view.width; + var scaleH = ( this.top - this.bottom ) / this.view.height; + + left += scaleW * ( this.view.offsetX / zoomW ); + right = left + scaleW * ( this.view.width / zoomW ); + top -= scaleH * ( this.view.offsetY / zoomH ); + bottom = top - scaleH * ( this.view.height / zoomH ); + + } + + this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far ); + + }, + + toJSON: function ( meta ) { + + var data = Object3D.prototype.toJSON.call( this, meta ); + + data.object.zoom = this.zoom; + data.object.left = this.left; + data.object.right = this.right; + data.object.top = this.top; + data.object.bottom = this.bottom; + data.object.near = this.near; + data.object.far = this.far; + + if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); + + return data; + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function WebGLIndexedBufferRenderer( gl, extensions, infoRender ) { + + var mode; + + function setMode( value ) { + + mode = value; + + } + + var type, size; + + function setIndex( index ) { + + if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) { + + type = gl.UNSIGNED_INT; + size = 4; + + } else if ( index.array instanceof Uint16Array ) { + + type = gl.UNSIGNED_SHORT; + size = 2; + + } else { + + type = gl.UNSIGNED_BYTE; + size = 1; + + } + + } + + function render( start, count ) { + + gl.drawElements( mode, count, type, start * size ); + + infoRender.calls ++; + infoRender.vertices += count; + + if ( mode === gl.TRIANGLES ) infoRender.faces += count / 3; + + } + + function renderInstances( geometry, start, count ) { + + var extension = extensions.get( 'ANGLE_instanced_arrays' ); + + if ( extension === null ) { + + console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); + return; + + } + + extension.drawElementsInstancedANGLE( mode, count, type, start * size, geometry.maxInstancedCount ); + + infoRender.calls ++; + infoRender.vertices += count * geometry.maxInstancedCount; + + if ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3; + + } + + return { + + setMode: setMode, + setIndex: setIndex, + render: render, + renderInstances: renderInstances + + }; + +} + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function WebGLBufferRenderer( gl, extensions, infoRender ) { + + var mode; + + function setMode( value ) { + + mode = value; + + } + + function render( start, count ) { + + gl.drawArrays( mode, start, count ); + + infoRender.calls ++; + infoRender.vertices += count; + + if ( mode === gl.TRIANGLES ) infoRender.faces += count / 3; + + } + + function renderInstances( geometry ) { + + var extension = extensions.get( 'ANGLE_instanced_arrays' ); + + if ( extension === null ) { + + console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); + return; + + } + + var position = geometry.attributes.position; + + var count = 0; + + if ( position.isInterleavedBufferAttribute ) { + + count = position.data.count; + + extension.drawArraysInstancedANGLE( mode, 0, count, geometry.maxInstancedCount ); + + } else { + + count = position.count; + + extension.drawArraysInstancedANGLE( mode, 0, count, geometry.maxInstancedCount ); + + } + + infoRender.calls ++; + infoRender.vertices += count * geometry.maxInstancedCount; + + if ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3; + + } + + return { + setMode: setMode, + render: render, + renderInstances: renderInstances + }; + +} + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function WebGLLights() { + + var lights = {}; + + return { + + get: function ( light ) { + + if ( lights[ light.id ] !== undefined ) { + + return lights[ light.id ]; + + } + + var uniforms; + + switch ( light.type ) { + + case 'DirectionalLight': + uniforms = { + direction: new Vector3(), + color: new Color(), + + shadow: false, + shadowBias: 0, + shadowRadius: 1, + shadowMapSize: new Vector2() + }; + break; + + case 'SpotLight': + uniforms = { + position: new Vector3(), + direction: new Vector3(), + color: new Color(), + distance: 0, + coneCos: 0, + penumbraCos: 0, + decay: 0, + + shadow: false, + shadowBias: 0, + shadowRadius: 1, + shadowMapSize: new Vector2() + }; + break; + + case 'PointLight': + uniforms = { + position: new Vector3(), + color: new Color(), + distance: 0, + decay: 0, + + shadow: false, + shadowBias: 0, + shadowRadius: 1, + shadowMapSize: new Vector2() + }; + break; + + case 'HemisphereLight': + uniforms = { + direction: new Vector3(), + skyColor: new Color(), + groundColor: new Color() + }; + break; + + case 'RectAreaLight': + uniforms = { + color: new Color(), + position: new Vector3(), + halfWidth: new Vector3(), + halfHeight: new Vector3() + // TODO (abelnation): set RectAreaLight shadow uniforms + }; + break; + + } + + lights[ light.id ] = uniforms; + + return uniforms; + + } + + }; + +} + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function addLineNumbers( string ) { + + var lines = string.split( '\n' ); + + for ( var i = 0; i < lines.length; i ++ ) { + + lines[ i ] = ( i + 1 ) + ': ' + lines[ i ]; + + } + + return lines.join( '\n' ); + +} + +function WebGLShader( gl, type, string ) { + + var shader = gl.createShader( type ); + + gl.shaderSource( shader, string ); + gl.compileShader( shader ); + + if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) { + + console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' ); + + } + + if ( gl.getShaderInfoLog( shader ) !== '' ) { + + console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', type === gl.VERTEX_SHADER ? 'vertex' : 'fragment', gl.getShaderInfoLog( shader ), addLineNumbers( string ) ); + + } + + // --enable-privileged-webgl-extension + // console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); + + return shader; + +} + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +var programIdCount = 0; + +function getEncodingComponents( encoding ) { + + switch ( encoding ) { + + case LinearEncoding: + return [ 'Linear','( value )' ]; + case sRGBEncoding: + return [ 'sRGB','( value )' ]; + case RGBEEncoding: + return [ 'RGBE','( value )' ]; + case RGBM7Encoding: + return [ 'RGBM','( value, 7.0 )' ]; + case RGBM16Encoding: + return [ 'RGBM','( value, 16.0 )' ]; + case RGBDEncoding: + return [ 'RGBD','( value, 256.0 )' ]; + case GammaEncoding: + return [ 'Gamma','( value, float( GAMMA_FACTOR ) )' ]; + default: + throw new Error( 'unsupported encoding: ' + encoding ); + + } + +} + +function getTexelDecodingFunction( functionName, encoding ) { + + var components = getEncodingComponents( encoding ); + return "vec4 " + functionName + "( vec4 value ) { return " + components[ 0 ] + "ToLinear" + components[ 1 ] + "; }"; + +} + +function getTexelEncodingFunction( functionName, encoding ) { + + var components = getEncodingComponents( encoding ); + return "vec4 " + functionName + "( vec4 value ) { return LinearTo" + components[ 0 ] + components[ 1 ] + "; }"; + +} + +function getToneMappingFunction( functionName, toneMapping ) { + + var toneMappingName; + + switch ( toneMapping ) { + + case LinearToneMapping: + toneMappingName = "Linear"; + break; + + case ReinhardToneMapping: + toneMappingName = "Reinhard"; + break; + + case Uncharted2ToneMapping: + toneMappingName = "Uncharted2"; + break; + + case CineonToneMapping: + toneMappingName = "OptimizedCineon"; + break; + + default: + throw new Error( 'unsupported toneMapping: ' + toneMapping ); + + } + + return "vec3 " + functionName + "( vec3 color ) { return " + toneMappingName + "ToneMapping( color ); }"; + +} + +function generateExtensions( extensions, parameters, rendererExtensions ) { + + extensions = extensions || {}; + + var chunks = [ + ( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '', + ( extensions.fragDepth || parameters.logarithmicDepthBuffer ) && rendererExtensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '', + ( extensions.drawBuffers ) && rendererExtensions.get( 'WEBGL_draw_buffers' ) ? '#extension GL_EXT_draw_buffers : require' : '', + ( extensions.shaderTextureLOD || parameters.envMap ) && rendererExtensions.get( 'EXT_shader_texture_lod' ) ? '#extension GL_EXT_shader_texture_lod : enable' : '' + ]; + + return chunks.filter( filterEmptyLine ).join( '\n' ); + +} + +function generateDefines( defines ) { + + var chunks = []; + + for ( var name in defines ) { + + var value = defines[ name ]; + + if ( value === false ) continue; + + chunks.push( '#define ' + name + ' ' + value ); + + } + + return chunks.join( '\n' ); + +} + +function fetchAttributeLocations( gl, program, identifiers ) { + + var attributes = {}; + + var n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES ); + + for ( var i = 0; i < n; i ++ ) { + + var info = gl.getActiveAttrib( program, i ); + var name = info.name; + + // console.log("THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:", name, i ); + + attributes[ name ] = gl.getAttribLocation( program, name ); + + } + + return attributes; + +} + +function filterEmptyLine( string ) { + + return string !== ''; + +} + +function replaceLightNums( string, parameters ) { + + return string + .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights ) + .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights ) + .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights ) + .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights ) + .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights ); + +} + +function parseIncludes( string ) { + + var pattern = /#include +<([\w\d.]+)>/g; + + function replace( match, include ) { + + var replace = ShaderChunk[ include ]; + + if ( replace === undefined ) { + + throw new Error( 'Can not resolve #include <' + include + '>' ); + + } + + return parseIncludes( replace ); + + } + + return string.replace( pattern, replace ); + +} + +function unrollLoops( string ) { + + var pattern = /for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g; + + function replace( match, start, end, snippet ) { + + var unroll = ''; + + for ( var i = parseInt( start ); i < parseInt( end ); i ++ ) { + + unroll += snippet.replace( /\[ i \]/g, '[ ' + i + ' ]' ); + + } + + return unroll; + + } + + return string.replace( pattern, replace ); + +} + +function WebGLProgram( renderer, code, material, parameters ) { + + var gl = renderer.context; + + var extensions = material.extensions; + var defines = material.defines; + + var vertexShader = material.__webglShader.vertexShader; + var fragmentShader = material.__webglShader.fragmentShader; + + var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; + + if ( parameters.shadowMapType === PCFShadowMap ) { + + shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; + + } else if ( parameters.shadowMapType === PCFSoftShadowMap ) { + + shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; + + } + + var envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; + var envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; + var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; + + if ( parameters.envMap ) { + + switch ( material.envMap.mapping ) { + + case CubeReflectionMapping: + case CubeRefractionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; + break; + + case CubeUVReflectionMapping: + case CubeUVRefractionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV'; + break; + + case EquirectangularReflectionMapping: + case EquirectangularRefractionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC'; + break; + + case SphericalReflectionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_SPHERE'; + break; + + } + + switch ( material.envMap.mapping ) { + + case CubeRefractionMapping: + case EquirectangularRefractionMapping: + envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; + break; + + } + + switch ( material.combine ) { + + case MultiplyOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; + break; + + case MixOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; + break; + + case AddOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; + break; + + } + + } + + var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0; + + // console.log( 'building new program ' ); + + // + + var customExtensions = generateExtensions( extensions, parameters, renderer.extensions ); + + var customDefines = generateDefines( defines ); + + // + + var program = gl.createProgram(); + + var prefixVertex, prefixFragment; + + if ( material.isRawShaderMaterial ) { + + prefixVertex = [ + + customDefines, + + '\n' + + ].filter( filterEmptyLine ).join( '\n' ); + + prefixFragment = [ + + customExtensions, + customDefines, + + '\n' + + ].filter( filterEmptyLine ).join( '\n' ); + + } else { + + prefixVertex = [ + + + 'precision ' + parameters.precision + ' float;', + 'precision ' + parameters.precision + ' int;', + + '#define SHADER_NAME ' + material.__webglShader.name, + + customDefines, + + parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', + + '#define GAMMA_FACTOR ' + gammaFactorDefine, + + '#define MAX_BONES ' + parameters.maxBones, + ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', + ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', + + + parameters.map ? '#define USE_MAP' : '', + parameters.envMap ? '#define USE_ENVMAP' : '', + parameters.envMap ? '#define ' + envMapModeDefine : '', + parameters.lightMap ? '#define USE_LIGHTMAP' : '', + parameters.aoMap ? '#define USE_AOMAP' : '', + parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', + parameters.bumpMap ? '#define USE_BUMPMAP' : '', + parameters.normalMap ? '#define USE_NORMALMAP' : '', + parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '', + parameters.specularMap ? '#define USE_SPECULARMAP' : '', + parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', + parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', + parameters.alphaMap ? '#define USE_ALPHAMAP' : '', + parameters.vertexColors ? '#define USE_COLOR' : '', + + parameters.flatShading ? '#define FLAT_SHADED' : '', + + parameters.skinning ? '#define USE_SKINNING' : '', + parameters.useVertexTexture ? '#define BONE_TEXTURE' : '', + + parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', + parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '', + parameters.doubleSided ? '#define DOUBLE_SIDED' : '', + parameters.flipSided ? '#define FLIP_SIDED' : '', + + '#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes, + + parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', + parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', + + parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', + + parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', + parameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '', + + 'uniform mat4 modelMatrix;', + 'uniform mat4 modelViewMatrix;', + 'uniform mat4 projectionMatrix;', + 'uniform mat4 viewMatrix;', + 'uniform mat3 normalMatrix;', + 'uniform vec3 cameraPosition;', + + 'attribute vec3 position;', + 'attribute vec3 normal;', + 'attribute vec2 uv;', + + '#ifdef USE_COLOR', + + ' attribute vec3 color;', + + '#endif', + + '#ifdef USE_MORPHTARGETS', + + ' attribute vec3 morphTarget0;', + ' attribute vec3 morphTarget1;', + ' attribute vec3 morphTarget2;', + ' attribute vec3 morphTarget3;', + + ' #ifdef USE_MORPHNORMALS', + + ' attribute vec3 morphNormal0;', + ' attribute vec3 morphNormal1;', + ' attribute vec3 morphNormal2;', + ' attribute vec3 morphNormal3;', + + ' #else', + + ' attribute vec3 morphTarget4;', + ' attribute vec3 morphTarget5;', + ' attribute vec3 morphTarget6;', + ' attribute vec3 morphTarget7;', + + ' #endif', + + '#endif', + + '#ifdef USE_SKINNING', + + ' attribute vec4 skinIndex;', + ' attribute vec4 skinWeight;', + + '#endif', + + '\n' + + ].filter( filterEmptyLine ).join( '\n' ); + + prefixFragment = [ + + customExtensions, + + 'precision ' + parameters.precision + ' float;', + 'precision ' + parameters.precision + ' int;', + + '#define SHADER_NAME ' + material.__webglShader.name, + + customDefines, + + parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '', + + '#define GAMMA_FACTOR ' + gammaFactorDefine, + + ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', + ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', + + parameters.map ? '#define USE_MAP' : '', + parameters.envMap ? '#define USE_ENVMAP' : '', + parameters.envMap ? '#define ' + envMapTypeDefine : '', + parameters.envMap ? '#define ' + envMapModeDefine : '', + parameters.envMap ? '#define ' + envMapBlendingDefine : '', + parameters.lightMap ? '#define USE_LIGHTMAP' : '', + parameters.aoMap ? '#define USE_AOMAP' : '', + parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', + parameters.bumpMap ? '#define USE_BUMPMAP' : '', + parameters.normalMap ? '#define USE_NORMALMAP' : '', + parameters.specularMap ? '#define USE_SPECULARMAP' : '', + parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', + parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', + parameters.alphaMap ? '#define USE_ALPHAMAP' : '', + parameters.vertexColors ? '#define USE_COLOR' : '', + + parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', + + parameters.flatShading ? '#define FLAT_SHADED' : '', + + parameters.doubleSided ? '#define DOUBLE_SIDED' : '', + parameters.flipSided ? '#define FLIP_SIDED' : '', + + '#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes, + '#define UNION_CLIPPING_PLANES ' + (parameters.numClippingPlanes - parameters.numClipIntersection), + + parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', + parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', + + parameters.premultipliedAlpha ? "#define PREMULTIPLIED_ALPHA" : '', + + parameters.physicallyCorrectLights ? "#define PHYSICALLY_CORRECT_LIGHTS" : '', + + parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', + parameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '', + + parameters.envMap && renderer.extensions.get( 'EXT_shader_texture_lod' ) ? '#define TEXTURE_LOD_EXT' : '', + + 'uniform mat4 viewMatrix;', + 'uniform vec3 cameraPosition;', + + ( parameters.toneMapping !== NoToneMapping ) ? "#define TONE_MAPPING" : '', + ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below + ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( "toneMapping", parameters.toneMapping ) : '', + + ( parameters.outputEncoding || parameters.mapEncoding || parameters.envMapEncoding || parameters.emissiveMapEncoding ) ? ShaderChunk[ 'encodings_pars_fragment' ] : '', // this code is required here because it is used by the various encoding/decoding function defined below + parameters.mapEncoding ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '', + parameters.envMapEncoding ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '', + parameters.emissiveMapEncoding ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '', + parameters.outputEncoding ? getTexelEncodingFunction( "linearToOutputTexel", parameters.outputEncoding ) : '', + + parameters.depthPacking ? "#define DEPTH_PACKING " + material.depthPacking : '', + + '\n' + + ].filter( filterEmptyLine ).join( '\n' ); + + } + + vertexShader = parseIncludes( vertexShader, parameters ); + vertexShader = replaceLightNums( vertexShader, parameters ); + + fragmentShader = parseIncludes( fragmentShader, parameters ); + fragmentShader = replaceLightNums( fragmentShader, parameters ); + + if ( ! material.isShaderMaterial ) { + + vertexShader = unrollLoops( vertexShader ); + fragmentShader = unrollLoops( fragmentShader ); + + } + + var vertexGlsl = prefixVertex + vertexShader; + var fragmentGlsl = prefixFragment + fragmentShader; + + // console.log( '*VERTEX*', vertexGlsl ); + // console.log( '*FRAGMENT*', fragmentGlsl ); + + var glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl ); + var glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl ); + + gl.attachShader( program, glVertexShader ); + gl.attachShader( program, glFragmentShader ); + + // Force a particular attribute to index 0. + + if ( material.index0AttributeName !== undefined ) { + + gl.bindAttribLocation( program, 0, material.index0AttributeName ); + + } else if ( parameters.morphTargets === true ) { + + // programs with morphTargets displace position out of attribute 0 + gl.bindAttribLocation( program, 0, 'position' ); + + } + + gl.linkProgram( program ); + + var programLog = gl.getProgramInfoLog( program ); + var vertexLog = gl.getShaderInfoLog( glVertexShader ); + var fragmentLog = gl.getShaderInfoLog( glFragmentShader ); + + var runnable = true; + var haveDiagnostics = true; + + // console.log( '**VERTEX**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) ); + // console.log( '**FRAGMENT**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) ); + + if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) { + + runnable = false; + + console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), 'gl.VALIDATE_STATUS', gl.getProgramParameter( program, gl.VALIDATE_STATUS ), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog ); + + } else if ( programLog !== '' ) { + + console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog ); + + } else if ( vertexLog === '' || fragmentLog === '' ) { + + haveDiagnostics = false; + + } + + if ( haveDiagnostics ) { + + this.diagnostics = { + + runnable: runnable, + material: material, + + programLog: programLog, + + vertexShader: { + + log: vertexLog, + prefix: prefixVertex + + }, + + fragmentShader: { + + log: fragmentLog, + prefix: prefixFragment + + } + + }; + + } + + // clean up + + gl.deleteShader( glVertexShader ); + gl.deleteShader( glFragmentShader ); + + // set up caching for uniform locations + + var cachedUniforms; + + this.getUniforms = function() { + + if ( cachedUniforms === undefined ) { + + cachedUniforms = + new WebGLUniforms( gl, program, renderer ); + + } + + return cachedUniforms; + + }; + + // set up caching for attribute locations + + var cachedAttributes; + + this.getAttributes = function() { + + if ( cachedAttributes === undefined ) { + + cachedAttributes = fetchAttributeLocations( gl, program ); + + } + + return cachedAttributes; + + }; + + // free resource + + this.destroy = function() { + + gl.deleteProgram( program ); + this.program = undefined; + + }; + + // DEPRECATED + + Object.defineProperties( this, { + + uniforms: { + get: function() { + + console.warn( 'THREE.WebGLProgram: .uniforms is now .getUniforms().' ); + return this.getUniforms(); + + } + }, + + attributes: { + get: function() { + + console.warn( 'THREE.WebGLProgram: .attributes is now .getAttributes().' ); + return this.getAttributes(); + + } + } + + } ); + + + // + + this.id = programIdCount ++; + this.code = code; + this.usedTimes = 1; + this.program = program; + this.vertexShader = glVertexShader; + this.fragmentShader = glFragmentShader; + + return this; + +} + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function WebGLPrograms( renderer, capabilities ) { + + var programs = []; + + var shaderIDs = { + MeshDepthMaterial: 'depth', + MeshNormalMaterial: 'normal', + MeshBasicMaterial: 'basic', + MeshLambertMaterial: 'lambert', + MeshPhongMaterial: 'phong', + MeshToonMaterial: 'phong', + MeshStandardMaterial: 'physical', + MeshPhysicalMaterial: 'physical', + LineBasicMaterial: 'basic', + LineDashedMaterial: 'dashed', + PointsMaterial: 'points' + }; + + var parameterNames = [ + "precision", "supportsVertexTextures", "map", "mapEncoding", "envMap", "envMapMode", "envMapEncoding", + "lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "displacementMap", "specularMap", + "roughnessMap", "metalnessMap", "gradientMap", + "alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp", + "flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning", + "maxBones", "useVertexTexture", "morphTargets", "morphNormals", + "maxMorphTargets", "maxMorphNormals", "premultipliedAlpha", + "numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights", + "shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights', + "alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking" + ]; + + + function allocateBones( object ) { + + if ( capabilities.floatVertexTextures && object && object.skeleton && object.skeleton.useVertexTexture ) { + + return 1024; + + } else { + + // default for when object is not specified + // ( for example when prebuilding shader to be used with multiple objects ) + // + // - leave some extra space for other uniforms + // - limit here is ANGLE's 254 max uniform vectors + // (up to 54 should be safe) + + var nVertexUniforms = capabilities.maxVertexUniforms; + var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); + + var maxBones = nVertexMatrices; + + if ( object !== undefined && (object && object.isSkinnedMesh) ) { + + maxBones = Math.min( object.skeleton.bones.length, maxBones ); + + if ( maxBones < object.skeleton.bones.length ) { + + console.warn( 'WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' ); + + } + + } + + return maxBones; + + } + + } + + function getTextureEncodingFromMap( map, gammaOverrideLinear ) { + + var encoding; + + if ( ! map ) { + + encoding = LinearEncoding; + + } else if ( map.isTexture ) { + + encoding = map.encoding; + + } else if ( map.isWebGLRenderTarget ) { + + console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." ); + encoding = map.texture.encoding; + + } + + // add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point. + if ( encoding === LinearEncoding && gammaOverrideLinear ) { + + encoding = GammaEncoding; + + } + + return encoding; + + } + + this.getParameters = function ( material, lights, fog, nClipPlanes, nClipIntersection, object ) { + + var shaderID = shaderIDs[ material.type ]; + + // heuristics to create shader parameters according to lights in the scene + // (not to blow over maxLights budget) + + var maxBones = allocateBones( object ); + var precision = renderer.getPrecision(); + + if ( material.precision !== null ) { + + precision = capabilities.getMaxPrecision( material.precision ); + + if ( precision !== material.precision ) { + + console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' ); + + } + + } + + var currentRenderTarget = renderer.getCurrentRenderTarget(); + + var parameters = { + + shaderID: shaderID, + + precision: precision, + supportsVertexTextures: capabilities.vertexTextures, + outputEncoding: getTextureEncodingFromMap( ( ! currentRenderTarget ) ? null : currentRenderTarget.texture, renderer.gammaOutput ), + map: !! material.map, + mapEncoding: getTextureEncodingFromMap( material.map, renderer.gammaInput ), + envMap: !! material.envMap, + envMapMode: material.envMap && material.envMap.mapping, + envMapEncoding: getTextureEncodingFromMap( material.envMap, renderer.gammaInput ), + envMapCubeUV: ( !! material.envMap ) && ( ( material.envMap.mapping === CubeUVReflectionMapping ) || ( material.envMap.mapping === CubeUVRefractionMapping ) ), + lightMap: !! material.lightMap, + aoMap: !! material.aoMap, + emissiveMap: !! material.emissiveMap, + emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ), + bumpMap: !! material.bumpMap, + normalMap: !! material.normalMap, + displacementMap: !! material.displacementMap, + roughnessMap: !! material.roughnessMap, + metalnessMap: !! material.metalnessMap, + specularMap: !! material.specularMap, + alphaMap: !! material.alphaMap, + + gradientMap: !! material.gradientMap, + + combine: material.combine, + + vertexColors: material.vertexColors, + + fog: !! fog, + useFog: material.fog, + fogExp: (fog && fog.isFogExp2), + + flatShading: material.shading === FlatShading, + + sizeAttenuation: material.sizeAttenuation, + logarithmicDepthBuffer: capabilities.logarithmicDepthBuffer, + + skinning: material.skinning, + maxBones: maxBones, + useVertexTexture: capabilities.floatVertexTextures && object && object.skeleton && object.skeleton.useVertexTexture, + + morphTargets: material.morphTargets, + morphNormals: material.morphNormals, + maxMorphTargets: renderer.maxMorphTargets, + maxMorphNormals: renderer.maxMorphNormals, + + numDirLights: lights.directional.length, + numPointLights: lights.point.length, + numSpotLights: lights.spot.length, + numRectAreaLights: lights.rectArea.length, + numHemiLights: lights.hemi.length, + + numClippingPlanes: nClipPlanes, + numClipIntersection: nClipIntersection, + + shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && lights.shadows.length > 0, + shadowMapType: renderer.shadowMap.type, + + toneMapping: renderer.toneMapping, + physicallyCorrectLights: renderer.physicallyCorrectLights, + + premultipliedAlpha: material.premultipliedAlpha, + + alphaTest: material.alphaTest, + doubleSided: material.side === DoubleSide, + flipSided: material.side === BackSide, + + depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false + + }; + + return parameters; + + }; + + this.getProgramCode = function ( material, parameters ) { + + var array = []; + + if ( parameters.shaderID ) { + + array.push( parameters.shaderID ); + + } else { + + array.push( material.fragmentShader ); + array.push( material.vertexShader ); + + } + + if ( material.defines !== undefined ) { + + for ( var name in material.defines ) { + + array.push( name ); + array.push( material.defines[ name ] ); + + } + + } + + for ( var i = 0; i < parameterNames.length; i ++ ) { + + array.push( parameters[ parameterNames[ i ] ] ); + + } + + return array.join(); + + }; + + this.acquireProgram = function ( material, parameters, code ) { + + var program; + + // Check if code has been already compiled + for ( var p = 0, pl = programs.length; p < pl; p ++ ) { + + var programInfo = programs[ p ]; + + if ( programInfo.code === code ) { + + program = programInfo; + ++ program.usedTimes; + + break; + + } + + } + + if ( program === undefined ) { + + program = new WebGLProgram( renderer, code, material, parameters ); + programs.push( program ); + + } + + return program; + + }; + + this.releaseProgram = function( program ) { + + if ( -- program.usedTimes === 0 ) { + + // Remove from unordered set + var i = programs.indexOf( program ); + programs[ i ] = programs[ programs.length - 1 ]; + programs.pop(); + + // Free WebGL resources + program.destroy(); + + } + + }; + + // Exposed for resource monitoring & error feedback via renderer.info: + this.programs = programs; + +} + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function WebGLGeometries( gl, properties, info ) { + + var geometries = {}; + + function onGeometryDispose( event ) { + + var geometry = event.target; + var buffergeometry = geometries[ geometry.id ]; + + if ( buffergeometry.index !== null ) { + + deleteAttribute( buffergeometry.index ); + + } + + deleteAttributes( buffergeometry.attributes ); + + geometry.removeEventListener( 'dispose', onGeometryDispose ); + + delete geometries[ geometry.id ]; + + // TODO + + var property = properties.get( geometry ); + + if ( property.wireframe ) { + + deleteAttribute( property.wireframe ); + + } + + properties.delete( geometry ); + + var bufferproperty = properties.get( buffergeometry ); + + if ( bufferproperty.wireframe ) { + + deleteAttribute( bufferproperty.wireframe ); + + } + + properties.delete( buffergeometry ); + + // + + info.memory.geometries --; + + } + + function getAttributeBuffer( attribute ) { + + if ( attribute.isInterleavedBufferAttribute ) { + + return properties.get( attribute.data ).__webglBuffer; + + } + + return properties.get( attribute ).__webglBuffer; + + } + + function deleteAttribute( attribute ) { + + var buffer = getAttributeBuffer( attribute ); + + if ( buffer !== undefined ) { + + gl.deleteBuffer( buffer ); + removeAttributeBuffer( attribute ); + + } + + } + + function deleteAttributes( attributes ) { + + for ( var name in attributes ) { + + deleteAttribute( attributes[ name ] ); + + } + + } + + function removeAttributeBuffer( attribute ) { + + if ( attribute.isInterleavedBufferAttribute ) { + + properties.delete( attribute.data ); + + } else { + + properties.delete( attribute ); + + } + + } + + return { + + get: function ( object ) { + + var geometry = object.geometry; + + if ( geometries[ geometry.id ] !== undefined ) { + + return geometries[ geometry.id ]; + + } + + geometry.addEventListener( 'dispose', onGeometryDispose ); + + var buffergeometry; + + if ( geometry.isBufferGeometry ) { + + buffergeometry = geometry; + + } else if ( geometry.isGeometry ) { + + if ( geometry._bufferGeometry === undefined ) { + + geometry._bufferGeometry = new BufferGeometry().setFromObject( object ); + + } + + buffergeometry = geometry._bufferGeometry; + + } + + geometries[ geometry.id ] = buffergeometry; + + info.memory.geometries ++; + + return buffergeometry; + + } + + }; + +} + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function WebGLObjects( gl, properties, info ) { + + var geometries = new WebGLGeometries( gl, properties, info ); + + // + + function update( object ) { + + // TODO: Avoid updating twice (when using shadowMap). Maybe add frame counter. + + var geometry = geometries.get( object ); + + if ( object.geometry.isGeometry ) { + + geometry.updateFromObject( object ); + + } + + var index = geometry.index; + var attributes = geometry.attributes; + + if ( index !== null ) { + + updateAttribute( index, gl.ELEMENT_ARRAY_BUFFER ); + + } + + for ( var name in attributes ) { + + updateAttribute( attributes[ name ], gl.ARRAY_BUFFER ); + + } + + // morph targets + + var morphAttributes = geometry.morphAttributes; + + for ( var name in morphAttributes ) { + + var array = morphAttributes[ name ]; + + for ( var i = 0, l = array.length; i < l; i ++ ) { + + updateAttribute( array[ i ], gl.ARRAY_BUFFER ); + + } + + } + + return geometry; + + } + + function updateAttribute( attribute, bufferType ) { + + var data = ( attribute.isInterleavedBufferAttribute ) ? attribute.data : attribute; + + var attributeProperties = properties.get( data ); + + if ( attributeProperties.__webglBuffer === undefined ) { + + createBuffer( attributeProperties, data, bufferType ); + + } else if ( attributeProperties.version !== data.version ) { + + updateBuffer( attributeProperties, data, bufferType ); + + } + + } + + function createBuffer( attributeProperties, data, bufferType ) { + + attributeProperties.__webglBuffer = gl.createBuffer(); + gl.bindBuffer( bufferType, attributeProperties.__webglBuffer ); + + var usage = data.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW; + + gl.bufferData( bufferType, data.array, usage ); + + var type = gl.FLOAT; + var array = data.array; + + if ( array instanceof Float32Array ) { + + type = gl.FLOAT; + + } else if ( array instanceof Float64Array ) { + + console.warn( "Unsupported data buffer format: Float64Array" ); + + } else if ( array instanceof Uint16Array ) { + + type = gl.UNSIGNED_SHORT; + + } else if ( array instanceof Int16Array ) { + + type = gl.SHORT; + + } else if ( array instanceof Uint32Array ) { + + type = gl.UNSIGNED_INT; + + } else if ( array instanceof Int32Array ) { + + type = gl.INT; + + } else if ( array instanceof Int8Array ) { + + type = gl.BYTE; + + } else if ( array instanceof Uint8Array ) { + + type = gl.UNSIGNED_BYTE; + + } + + attributeProperties.bytesPerElement = array.BYTES_PER_ELEMENT; + attributeProperties.type = type; + attributeProperties.version = data.version; + + data.onUploadCallback(); + + } + + function updateBuffer( attributeProperties, data, bufferType ) { + + gl.bindBuffer( bufferType, attributeProperties.__webglBuffer ); + + if ( data.dynamic === false ) { + + gl.bufferData( bufferType, data.array, gl.STATIC_DRAW ); + + } else if ( data.updateRange.count === - 1 ) { + + // Not using update ranges + + gl.bufferSubData( bufferType, 0, data.array ); + + } else if ( data.updateRange.count === 0 ) { + + console.error( 'THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually.' ); + + } else { + + gl.bufferSubData( bufferType, data.updateRange.offset * data.array.BYTES_PER_ELEMENT, + data.array.subarray( data.updateRange.offset, data.updateRange.offset + data.updateRange.count ) ); + + data.updateRange.count = 0; // reset range + + } + + attributeProperties.version = data.version; + + } + + function getAttributeBuffer( attribute ) { + + if ( attribute.isInterleavedBufferAttribute ) { + + return properties.get( attribute.data ).__webglBuffer; + + } + + return properties.get( attribute ).__webglBuffer; + + } + + function getAttributeProperties( attribute ) { + + if ( attribute.isInterleavedBufferAttribute ) { + + return properties.get( attribute.data ); + + } + + return properties.get( attribute ); + + } + + function getWireframeAttribute( geometry ) { + + var property = properties.get( geometry ); + + if ( property.wireframe !== undefined ) { + + return property.wireframe; + + } + + var indices = []; + + var index = geometry.index; + var attributes = geometry.attributes; + + // console.time( 'wireframe' ); + + if ( index !== null ) { + + var array = index.array; + + for ( var i = 0, l = array.length; i < l; i += 3 ) { + + var a = array[ i + 0 ]; + var b = array[ i + 1 ]; + var c = array[ i + 2 ]; + + indices.push( a, b, b, c, c, a ); + + } + + } else { + + var array = attributes.position.array; + + for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { + + var a = i + 0; + var b = i + 1; + var c = i + 2; + + indices.push( a, b, b, c, c, a ); + + } + + } + + // console.timeEnd( 'wireframe' ); + + var attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); + + updateAttribute( attribute, gl.ELEMENT_ARRAY_BUFFER ); + + property.wireframe = attribute; + + return attribute; + + } + + return { + + getAttributeBuffer: getAttributeBuffer, + getAttributeProperties: getAttributeProperties, + getWireframeAttribute: getWireframeAttribute, + + update: update + + }; + +} + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, info ) { + + var _infoMemory = info.memory; + var _isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && _gl instanceof WebGL2RenderingContext ); + + // + + function clampToMaxSize( image, maxSize ) { + + if ( image.width > maxSize || image.height > maxSize ) { + + // Warning: Scaling through the canvas will only work with images that use + // premultiplied alpha. + + var scale = maxSize / Math.max( image.width, image.height ); + + var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); + canvas.width = Math.floor( image.width * scale ); + canvas.height = Math.floor( image.height * scale ); + + var context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height ); + + console.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image ); + + return canvas; + + } + + return image; + + } + + function isPowerOfTwo( image ) { + + return _Math.isPowerOfTwo( image.width ) && _Math.isPowerOfTwo( image.height ); + + } + + function makePowerOfTwo( image ) { + + if ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement ) { + + var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); + canvas.width = _Math.nearestPowerOfTwo( image.width ); + canvas.height = _Math.nearestPowerOfTwo( image.height ); + + var context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0, canvas.width, canvas.height ); + + console.warn( 'THREE.WebGLRenderer: image is not power of two (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image ); + + return canvas; + + } + + return image; + + } + + function textureNeedsPowerOfTwo( texture ) { + + return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) || + ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ); + + } + + // Fallback filters for non-power-of-2 textures + + function filterFallback( f ) { + + if ( f === NearestFilter || f === NearestMipMapNearestFilter || f === NearestMipMapLinearFilter ) { + + return _gl.NEAREST; + + } + + return _gl.LINEAR; + + } + + // + + function onTextureDispose( event ) { + + var texture = event.target; + + texture.removeEventListener( 'dispose', onTextureDispose ); + + deallocateTexture( texture ); + + _infoMemory.textures --; + + + } + + function onRenderTargetDispose( event ) { + + var renderTarget = event.target; + + renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); + + deallocateRenderTarget( renderTarget ); + + _infoMemory.textures --; + + } + + // + + function deallocateTexture( texture ) { + + var textureProperties = properties.get( texture ); + + if ( texture.image && textureProperties.__image__webglTextureCube ) { + + // cube texture + + _gl.deleteTexture( textureProperties.__image__webglTextureCube ); + + } else { + + // 2D texture + + if ( textureProperties.__webglInit === undefined ) return; + + _gl.deleteTexture( textureProperties.__webglTexture ); + + } + + // remove all webgl properties + properties.delete( texture ); + + } + + function deallocateRenderTarget( renderTarget ) { + + var renderTargetProperties = properties.get( renderTarget ); + var textureProperties = properties.get( renderTarget.texture ); + + if ( ! renderTarget ) return; + + if ( textureProperties.__webglTexture !== undefined ) { + + _gl.deleteTexture( textureProperties.__webglTexture ); + + } + + if ( renderTarget.depthTexture ) { + + renderTarget.depthTexture.dispose(); + + } + + if ( renderTarget.isWebGLRenderTargetCube ) { + + for ( var i = 0; i < 6; i ++ ) { + + _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); + if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] ); + + } + + } else { + + _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); + if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer ); + + } + + properties.delete( renderTarget.texture ); + properties.delete( renderTarget ); + + } + + // + + + + function setTexture2D( texture, slot ) { + + var textureProperties = properties.get( texture ); + + if ( texture.version > 0 && textureProperties.__version !== texture.version ) { + + var image = texture.image; + + if ( image === undefined ) { + + console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined', texture ); + + } else if ( image.complete === false ) { + + console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete', texture ); + + } else { + + uploadTexture( textureProperties, texture, slot ); + return; + + } + + } + + state.activeTexture( _gl.TEXTURE0 + slot ); + state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); + + } + + function setTextureCube( texture, slot ) { + + var textureProperties = properties.get( texture ); + + if ( texture.image.length === 6 ) { + + if ( texture.version > 0 && textureProperties.__version !== texture.version ) { + + if ( ! textureProperties.__image__webglTextureCube ) { + + texture.addEventListener( 'dispose', onTextureDispose ); + + textureProperties.__image__webglTextureCube = _gl.createTexture(); + + _infoMemory.textures ++; + + } + + state.activeTexture( _gl.TEXTURE0 + slot ); + state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube ); + + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); + + var isCompressed = ( texture && texture.isCompressedTexture ); + var isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture ); + + var cubeImage = []; + + for ( var i = 0; i < 6; i ++ ) { + + if ( ! isCompressed && ! isDataTexture ) { + + cubeImage[ i ] = clampToMaxSize( texture.image[ i ], capabilities.maxCubemapSize ); + + } else { + + cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; + + } + + } + + var image = cubeImage[ 0 ], + isPowerOfTwoImage = isPowerOfTwo( image ), + glFormat = paramThreeToGL( texture.format ), + glType = paramThreeToGL( texture.type ); + + setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isPowerOfTwoImage ); + + for ( var i = 0; i < 6; i ++ ) { + + if ( ! isCompressed ) { + + if ( isDataTexture ) { + + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); + + } else { + + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] ); + + } + + } else { + + var mipmap, mipmaps = cubeImage[ i ].mipmaps; + + for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { + + mipmap = mipmaps[ j ]; + + if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) { + + if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) { + + state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + + } else { + + console.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()" ); + + } + + } else { + + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + + } + + } + + } + + } + + if ( texture.generateMipmaps && isPowerOfTwoImage ) { + + _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + + } + + textureProperties.__version = texture.version; + + if ( texture.onUpdate ) texture.onUpdate( texture ); + + } else { + + state.activeTexture( _gl.TEXTURE0 + slot ); + state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube ); + + } + + } + + } + + function setTextureCubeDynamic( texture, slot ) { + + state.activeTexture( _gl.TEXTURE0 + slot ); + state.bindTexture( _gl.TEXTURE_CUBE_MAP, properties.get( texture ).__webglTexture ); + + } + + function setTextureParameters( textureType, texture, isPowerOfTwoImage ) { + + var extension; + + if ( isPowerOfTwoImage ) { + + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) ); + + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) ); + + } else { + + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); + + if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) { + + console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.', texture ); + + } + + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); + + if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) { + + console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.', texture ); + + } + + } + + extension = extensions.get( 'EXT_texture_filter_anisotropic' ); + + if ( extension ) { + + if ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return; + if ( texture.type === HalfFloatType && extensions.get( 'OES_texture_half_float_linear' ) === null ) return; + + if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) { + + _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) ); + properties.get( texture ).__currentAnisotropy = texture.anisotropy; + + } + + } + + } + + function uploadTexture( textureProperties, texture, slot ) { + + if ( textureProperties.__webglInit === undefined ) { + + textureProperties.__webglInit = true; + + texture.addEventListener( 'dispose', onTextureDispose ); + + textureProperties.__webglTexture = _gl.createTexture(); + + _infoMemory.textures ++; + + } + + state.activeTexture( _gl.TEXTURE0 + slot ); + state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); + + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); + _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); + _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); + + var image = clampToMaxSize( texture.image, capabilities.maxTextureSize ); + + if ( textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( image ) === false ) { + + image = makePowerOfTwo( image ); + + } + + var isPowerOfTwoImage = isPowerOfTwo( image ), + glFormat = paramThreeToGL( texture.format ), + glType = paramThreeToGL( texture.type ); + + setTextureParameters( _gl.TEXTURE_2D, texture, isPowerOfTwoImage ); + + var mipmap, mipmaps = texture.mipmaps; + + if ( texture.isDepthTexture ) { + + // populate depth texture with dummy data + + var internalFormat = _gl.DEPTH_COMPONENT; + + if ( texture.type === FloatType ) { + + if ( !_isWebGL2 ) throw new Error('Float Depth Texture only supported in WebGL2.0'); + internalFormat = _gl.DEPTH_COMPONENT32F; + + } else if ( _isWebGL2 ) { + + // WebGL 2.0 requires signed internalformat for glTexImage2D + internalFormat = _gl.DEPTH_COMPONENT16; + + } + + if ( texture.format === DepthFormat && internalFormat === _gl.DEPTH_COMPONENT ) { + + // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are + // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT + // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) + if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) { + + console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' ); + + texture.type = UnsignedShortType; + glType = paramThreeToGL( texture.type ); + + } + + } + + // Depth stencil textures need the DEPTH_STENCIL internal format + // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) + if ( texture.format === DepthStencilFormat ) { + + internalFormat = _gl.DEPTH_STENCIL; + + // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are + // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL. + // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) + if ( texture.type !== UnsignedInt248Type ) { + + console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' ); + + texture.type = UnsignedInt248Type; + glType = paramThreeToGL( texture.type ); + + } + + } + + state.texImage2D( _gl.TEXTURE_2D, 0, internalFormat, image.width, image.height, 0, glFormat, glType, null ); + + } else if ( texture.isDataTexture ) { + + // use manually created mipmaps if available + // if there are no manual mipmaps + // set 0 level mipmap and then use GL to generate other mipmap levels + + if ( mipmaps.length > 0 && isPowerOfTwoImage ) { + + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + + mipmap = mipmaps[ i ]; + state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + + } + + texture.generateMipmaps = false; + + } else { + + state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data ); + + } + + } else if ( texture.isCompressedTexture ) { + + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + + mipmap = mipmaps[ i ]; + + if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) { + + if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) { + + state.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + + } else { + + console.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()" ); + + } + + } else { + + state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + + } + + } + + } else { + + // regular Texture (image, video, canvas) + + // use manually created mipmaps if available + // if there are no manual mipmaps + // set 0 level mipmap and then use GL to generate other mipmap levels + + if ( mipmaps.length > 0 && isPowerOfTwoImage ) { + + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + + mipmap = mipmaps[ i ]; + state.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap ); + + } + + texture.generateMipmaps = false; + + } else { + + state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, image ); + + } + + } + + if ( texture.generateMipmaps && isPowerOfTwoImage ) _gl.generateMipmap( _gl.TEXTURE_2D ); + + textureProperties.__version = texture.version; + + if ( texture.onUpdate ) texture.onUpdate( texture ); + + } + + // Render targets + + // Setup storage for target texture and bind it to correct framebuffer + function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) { + + var glFormat = paramThreeToGL( renderTarget.texture.format ); + var glType = paramThreeToGL( renderTarget.texture.type ); + state.texImage2D( textureTarget, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); + _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 ); + _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); + + } + + // Setup storage for internal depth/stencil buffers and bind to correct framebuffer + function setupRenderBufferStorage( renderbuffer, renderTarget ) { + + _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); + + if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { + + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + + } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { + + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + + } else { + + // FIXME: We don't support !depth !stencil + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height ); + + } + + _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); + + } + + // Setup resources for a Depth Texture for a FBO (needs an extension) + function setupDepthTexture( framebuffer, renderTarget ) { + + var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube ); + if ( isCube ) throw new Error('Depth Texture with cube render targets is not supported!'); + + _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + + if ( !( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) { + + throw new Error('renderTarget.depthTexture must be an instance of THREE.DepthTexture'); + + } + + // upload an empty depth texture with framebuffer size + if ( !properties.get( renderTarget.depthTexture ).__webglTexture || + renderTarget.depthTexture.image.width !== renderTarget.width || + renderTarget.depthTexture.image.height !== renderTarget.height ) { + renderTarget.depthTexture.image.width = renderTarget.width; + renderTarget.depthTexture.image.height = renderTarget.height; + renderTarget.depthTexture.needsUpdate = true; + } + + setTexture2D( renderTarget.depthTexture, 0 ); + + var webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture; + + if ( renderTarget.depthTexture.format === DepthFormat ) { + + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); + + } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) { + + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); + + } else { + + throw new Error('Unknown depthTexture format') + + } + + } + + // Setup GL resources for a non-texture depth buffer + function setupDepthRenderbuffer( renderTarget ) { + + var renderTargetProperties = properties.get( renderTarget ); + + var isCube = ( renderTarget.isWebGLRenderTargetCube === true ); + + if ( renderTarget.depthTexture ) { + + if ( isCube ) throw new Error('target.depthTexture not supported in Cube render targets'); + + setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget ); + + } else { + + if ( isCube ) { + + renderTargetProperties.__webglDepthbuffer = []; + + for ( var i = 0; i < 6; i ++ ) { + + _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] ); + renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer(); + setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget ); + + } + + } else { + + _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); + renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); + setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget ); + + } + + } + + _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); + + } + + // Set up GL resources for the render target + function setupRenderTarget( renderTarget ) { + + var renderTargetProperties = properties.get( renderTarget ); + var textureProperties = properties.get( renderTarget.texture ); + + renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); + + textureProperties.__webglTexture = _gl.createTexture(); + + _infoMemory.textures ++; + + var isCube = ( renderTarget.isWebGLRenderTargetCube === true ); + var isTargetPowerOfTwo = isPowerOfTwo( renderTarget ); + + // Setup framebuffer + + if ( isCube ) { + + renderTargetProperties.__webglFramebuffer = []; + + for ( var i = 0; i < 6; i ++ ) { + + renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); + + } + + } else { + + renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); + + } + + // Setup color buffer + + if ( isCube ) { + + state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture ); + setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, isTargetPowerOfTwo ); + + for ( var i = 0; i < 6; i ++ ) { + + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i ); + + } + + if ( renderTarget.texture.generateMipmaps && isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + state.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); + + } else { + + state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); + setTextureParameters( _gl.TEXTURE_2D, renderTarget.texture, isTargetPowerOfTwo ); + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D ); + + if ( renderTarget.texture.generateMipmaps && isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); + state.bindTexture( _gl.TEXTURE_2D, null ); + + } + + // Setup depth and stencil buffers + + if ( renderTarget.depthBuffer ) { + + setupDepthRenderbuffer( renderTarget ); + + } + + } + + function updateRenderTargetMipmap( renderTarget ) { + + var texture = renderTarget.texture; + + if ( texture.generateMipmaps && isPowerOfTwo( renderTarget ) && + texture.minFilter !== NearestFilter && + texture.minFilter !== LinearFilter ) { + + var target = (renderTarget && renderTarget.isWebGLRenderTargetCube) ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D; + var webglTexture = properties.get( texture ).__webglTexture; + + state.bindTexture( target, webglTexture ); + _gl.generateMipmap( target ); + state.bindTexture( target, null ); + + } + + } + + this.setTexture2D = setTexture2D; + this.setTextureCube = setTextureCube; + this.setTextureCubeDynamic = setTextureCubeDynamic; + this.setupRenderTarget = setupRenderTarget; + this.updateRenderTargetMipmap = updateRenderTargetMipmap; + +} + +/** + * @author fordacious / fordacious.github.io + */ + +function WebGLProperties() { + + var properties = {}; + + return { + + get: function ( object ) { + + var uuid = object.uuid; + var map = properties[ uuid ]; + + if ( map === undefined ) { + + map = {}; + properties[ uuid ] = map; + + } + + return map; + + }, + + delete: function ( object ) { + + delete properties[ object.uuid ]; + + }, + + clear: function () { + + properties = {}; + + } + + }; + +} + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function WebGLState( gl, extensions, paramThreeToGL ) { + + function ColorBuffer() { + + var locked = false; + + var color = new Vector4(); + var currentColorMask = null; + var currentColorClear = new Vector4(); + + return { + + setMask: function ( colorMask ) { + + if ( currentColorMask !== colorMask && ! locked ) { + + gl.colorMask( colorMask, colorMask, colorMask, colorMask ); + currentColorMask = colorMask; + + } + + }, + + setLocked: function ( lock ) { + + locked = lock; + + }, + + setClear: function ( r, g, b, a, premultipliedAlpha ) { + + if ( premultipliedAlpha === true ) { + + r *= a; g *= a; b *= a; + + } + + color.set( r, g, b, a ); + + if ( currentColorClear.equals( color ) === false ) { + + gl.clearColor( r, g, b, a ); + currentColorClear.copy( color ); + + } + + }, + + reset: function () { + + locked = false; + + currentColorMask = null; + currentColorClear.set( 0, 0, 0, 1 ); + + } + + }; + + } + + function DepthBuffer() { + + var locked = false; + + var currentDepthMask = null; + var currentDepthFunc = null; + var currentDepthClear = null; + + return { + + setTest: function ( depthTest ) { + + if ( depthTest ) { + + enable( gl.DEPTH_TEST ); + + } else { + + disable( gl.DEPTH_TEST ); + + } + + }, + + setMask: function ( depthMask ) { + + if ( currentDepthMask !== depthMask && ! locked ) { + + gl.depthMask( depthMask ); + currentDepthMask = depthMask; + + } + + }, + + setFunc: function ( depthFunc ) { + + if ( currentDepthFunc !== depthFunc ) { + + if ( depthFunc ) { + + switch ( depthFunc ) { + + case NeverDepth: + + gl.depthFunc( gl.NEVER ); + break; + + case AlwaysDepth: + + gl.depthFunc( gl.ALWAYS ); + break; + + case LessDepth: + + gl.depthFunc( gl.LESS ); + break; + + case LessEqualDepth: + + gl.depthFunc( gl.LEQUAL ); + break; + + case EqualDepth: + + gl.depthFunc( gl.EQUAL ); + break; + + case GreaterEqualDepth: + + gl.depthFunc( gl.GEQUAL ); + break; + + case GreaterDepth: + + gl.depthFunc( gl.GREATER ); + break; + + case NotEqualDepth: + + gl.depthFunc( gl.NOTEQUAL ); + break; + + default: + + gl.depthFunc( gl.LEQUAL ); + + } + + } else { + + gl.depthFunc( gl.LEQUAL ); + + } + + currentDepthFunc = depthFunc; + + } + + }, + + setLocked: function ( lock ) { + + locked = lock; + + }, + + setClear: function ( depth ) { + + if ( currentDepthClear !== depth ) { + + gl.clearDepth( depth ); + currentDepthClear = depth; + + } + + }, + + reset: function () { + + locked = false; + + currentDepthMask = null; + currentDepthFunc = null; + currentDepthClear = null; + + } + + }; + + } + + function StencilBuffer() { + + var locked = false; + + var currentStencilMask = null; + var currentStencilFunc = null; + var currentStencilRef = null; + var currentStencilFuncMask = null; + var currentStencilFail = null; + var currentStencilZFail = null; + var currentStencilZPass = null; + var currentStencilClear = null; + + return { + + setTest: function ( stencilTest ) { + + if ( stencilTest ) { + + enable( gl.STENCIL_TEST ); + + } else { + + disable( gl.STENCIL_TEST ); + + } + + }, + + setMask: function ( stencilMask ) { + + if ( currentStencilMask !== stencilMask && ! locked ) { + + gl.stencilMask( stencilMask ); + currentStencilMask = stencilMask; + + } + + }, + + setFunc: function ( stencilFunc, stencilRef, stencilMask ) { + + if ( currentStencilFunc !== stencilFunc || + currentStencilRef !== stencilRef || + currentStencilFuncMask !== stencilMask ) { + + gl.stencilFunc( stencilFunc, stencilRef, stencilMask ); + + currentStencilFunc = stencilFunc; + currentStencilRef = stencilRef; + currentStencilFuncMask = stencilMask; + + } + + }, + + setOp: function ( stencilFail, stencilZFail, stencilZPass ) { + + if ( currentStencilFail !== stencilFail || + currentStencilZFail !== stencilZFail || + currentStencilZPass !== stencilZPass ) { + + gl.stencilOp( stencilFail, stencilZFail, stencilZPass ); + + currentStencilFail = stencilFail; + currentStencilZFail = stencilZFail; + currentStencilZPass = stencilZPass; + + } + + }, + + setLocked: function ( lock ) { + + locked = lock; + + }, + + setClear: function ( stencil ) { + + if ( currentStencilClear !== stencil ) { + + gl.clearStencil( stencil ); + currentStencilClear = stencil; + + } + + }, + + reset: function () { + + locked = false; + + currentStencilMask = null; + currentStencilFunc = null; + currentStencilRef = null; + currentStencilFuncMask = null; + currentStencilFail = null; + currentStencilZFail = null; + currentStencilZPass = null; + currentStencilClear = null; + + } + + }; + + } + + // + + var colorBuffer = new ColorBuffer(); + var depthBuffer = new DepthBuffer(); + var stencilBuffer = new StencilBuffer(); + + var maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); + var newAttributes = new Uint8Array( maxVertexAttributes ); + var enabledAttributes = new Uint8Array( maxVertexAttributes ); + var attributeDivisors = new Uint8Array( maxVertexAttributes ); + + var capabilities = {}; + + var compressedTextureFormats = null; + + var currentBlending = null; + var currentBlendEquation = null; + var currentBlendSrc = null; + var currentBlendDst = null; + var currentBlendEquationAlpha = null; + var currentBlendSrcAlpha = null; + var currentBlendDstAlpha = null; + var currentPremultipledAlpha = false; + + var currentFlipSided = null; + var currentCullFace = null; + + var currentLineWidth = null; + + var currentPolygonOffsetFactor = null; + var currentPolygonOffsetUnits = null; + + var currentScissorTest = null; + + var maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); + + var version = parseFloat( /^WebGL\ ([0-9])/.exec( gl.getParameter( gl.VERSION ) )[ 1 ] ); + var lineWidthAvailable = parseFloat( version ) >= 1.0; + + var currentTextureSlot = null; + var currentBoundTextures = {}; + + var currentScissor = new Vector4(); + var currentViewport = new Vector4(); + + function createTexture( type, target, count ) { + + var data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4. + var texture = gl.createTexture(); + + gl.bindTexture( type, texture ); + gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); + gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); + + for ( var i = 0; i < count; i ++ ) { + + gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); + + } + + return texture; + + } + + var emptyTextures = {}; + emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 ); + emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 ); + + // + + function init() { + + colorBuffer.setClear( 0, 0, 0, 1 ); + depthBuffer.setClear( 1 ); + stencilBuffer.setClear( 0 ); + + enable( gl.DEPTH_TEST ); + setDepthFunc( LessEqualDepth ); + + setFlipSided( false ); + setCullFace( CullFaceBack ); + enable( gl.CULL_FACE ); + + enable( gl.BLEND ); + setBlending( NormalBlending ); + + } + + function initAttributes() { + + for ( var i = 0, l = newAttributes.length; i < l; i ++ ) { + + newAttributes[ i ] = 0; + + } + + } + + function enableAttribute( attribute ) { + + newAttributes[ attribute ] = 1; + + if ( enabledAttributes[ attribute ] === 0 ) { + + gl.enableVertexAttribArray( attribute ); + enabledAttributes[ attribute ] = 1; + + } + + if ( attributeDivisors[ attribute ] !== 0 ) { + + var extension = extensions.get( 'ANGLE_instanced_arrays' ); + + extension.vertexAttribDivisorANGLE( attribute, 0 ); + attributeDivisors[ attribute ] = 0; + + } + + } + + function enableAttributeAndDivisor( attribute, meshPerAttribute, extension ) { + + newAttributes[ attribute ] = 1; + + if ( enabledAttributes[ attribute ] === 0 ) { + + gl.enableVertexAttribArray( attribute ); + enabledAttributes[ attribute ] = 1; + + } + + if ( attributeDivisors[ attribute ] !== meshPerAttribute ) { + + extension.vertexAttribDivisorANGLE( attribute, meshPerAttribute ); + attributeDivisors[ attribute ] = meshPerAttribute; + + } + + } + + function disableUnusedAttributes() { + + for ( var i = 0, l = enabledAttributes.length; i !== l; ++ i ) { + + if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { + + gl.disableVertexAttribArray( i ); + enabledAttributes[ i ] = 0; + + } + + } + + } + + function enable( id ) { + + if ( capabilities[ id ] !== true ) { + + gl.enable( id ); + capabilities[ id ] = true; + + } + + } + + function disable( id ) { + + if ( capabilities[ id ] !== false ) { + + gl.disable( id ); + capabilities[ id ] = false; + + } + + } + + function getCompressedTextureFormats() { + + if ( compressedTextureFormats === null ) { + + compressedTextureFormats = []; + + if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) || + extensions.get( 'WEBGL_compressed_texture_s3tc' ) || + extensions.get( 'WEBGL_compressed_texture_etc1' ) ) { + + var formats = gl.getParameter( gl.COMPRESSED_TEXTURE_FORMATS ); + + for ( var i = 0; i < formats.length; i ++ ) { + + compressedTextureFormats.push( formats[ i ] ); + + } + + } + + } + + return compressedTextureFormats; + + } + + function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { + + if ( blending !== NoBlending ) { + + enable( gl.BLEND ); + + } else { + + disable( gl.BLEND ); + + } + + if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) { + + if ( blending === AdditiveBlending ) { + + if ( premultipliedAlpha ) { + + gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); + gl.blendFuncSeparate( gl.ONE, gl.ONE, gl.ONE, gl.ONE ); + + } else { + + gl.blendEquation( gl.FUNC_ADD ); + gl.blendFunc( gl.SRC_ALPHA, gl.ONE ); + + } + + } else if ( blending === SubtractiveBlending ) { + + if ( premultipliedAlpha ) { + + gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); + gl.blendFuncSeparate( gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA ); + + } else { + + gl.blendEquation( gl.FUNC_ADD ); + gl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR ); + + } + + } else if ( blending === MultiplyBlending ) { + + if ( premultipliedAlpha ) { + + gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); + gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA ); + + } else { + + gl.blendEquation( gl.FUNC_ADD ); + gl.blendFunc( gl.ZERO, gl.SRC_COLOR ); + + } + + } else { + + if ( premultipliedAlpha ) { + + gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); + gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); + + } else { + + gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); + gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); + + } + + } + + currentBlending = blending; + currentPremultipledAlpha = premultipliedAlpha; + + } + + if ( blending === CustomBlending ) { + + blendEquationAlpha = blendEquationAlpha || blendEquation; + blendSrcAlpha = blendSrcAlpha || blendSrc; + blendDstAlpha = blendDstAlpha || blendDst; + + if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { + + gl.blendEquationSeparate( paramThreeToGL( blendEquation ), paramThreeToGL( blendEquationAlpha ) ); + + currentBlendEquation = blendEquation; + currentBlendEquationAlpha = blendEquationAlpha; + + } + + if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { + + gl.blendFuncSeparate( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ), paramThreeToGL( blendSrcAlpha ), paramThreeToGL( blendDstAlpha ) ); + + currentBlendSrc = blendSrc; + currentBlendDst = blendDst; + currentBlendSrcAlpha = blendSrcAlpha; + currentBlendDstAlpha = blendDstAlpha; + + } + + } else { + + currentBlendEquation = null; + currentBlendSrc = null; + currentBlendDst = null; + currentBlendEquationAlpha = null; + currentBlendSrcAlpha = null; + currentBlendDstAlpha = null; + + } + + } + + // TODO Deprecate + + function setColorWrite( colorWrite ) { + + colorBuffer.setMask( colorWrite ); + + } + + function setDepthTest( depthTest ) { + + depthBuffer.setTest( depthTest ); + + } + + function setDepthWrite( depthWrite ) { + + depthBuffer.setMask( depthWrite ); + + } + + function setDepthFunc( depthFunc ) { + + depthBuffer.setFunc( depthFunc ); + + } + + function setStencilTest( stencilTest ) { + + stencilBuffer.setTest( stencilTest ); + + } + + function setStencilWrite( stencilWrite ) { + + stencilBuffer.setMask( stencilWrite ); + + } + + function setStencilFunc( stencilFunc, stencilRef, stencilMask ) { + + stencilBuffer.setFunc( stencilFunc, stencilRef, stencilMask ); + + } + + function setStencilOp( stencilFail, stencilZFail, stencilZPass ) { + + stencilBuffer.setOp( stencilFail, stencilZFail, stencilZPass ); + + } + + // + + function setFlipSided( flipSided ) { + + if ( currentFlipSided !== flipSided ) { + + if ( flipSided ) { + + gl.frontFace( gl.CW ); + + } else { + + gl.frontFace( gl.CCW ); + + } + + currentFlipSided = flipSided; + + } + + } + + function setCullFace( cullFace ) { + + if ( cullFace !== CullFaceNone ) { + + enable( gl.CULL_FACE ); + + if ( cullFace !== currentCullFace ) { + + if ( cullFace === CullFaceBack ) { + + gl.cullFace( gl.BACK ); + + } else if ( cullFace === CullFaceFront ) { + + gl.cullFace( gl.FRONT ); + + } else { + + gl.cullFace( gl.FRONT_AND_BACK ); + + } + + } + + } else { + + disable( gl.CULL_FACE ); + + } + + currentCullFace = cullFace; + + } + + function setLineWidth( width ) { + + if ( width !== currentLineWidth ) { + + if ( lineWidthAvailable ) gl.lineWidth( width ); + + currentLineWidth = width; + + } + + } + + function setPolygonOffset( polygonOffset, factor, units ) { + + if ( polygonOffset ) { + + enable( gl.POLYGON_OFFSET_FILL ); + + if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) { + + gl.polygonOffset( factor, units ); + + currentPolygonOffsetFactor = factor; + currentPolygonOffsetUnits = units; + + } + + } else { + + disable( gl.POLYGON_OFFSET_FILL ); + + } + + } + + function getScissorTest() { + + return currentScissorTest; + + } + + function setScissorTest( scissorTest ) { + + currentScissorTest = scissorTest; + + if ( scissorTest ) { + + enable( gl.SCISSOR_TEST ); + + } else { + + disable( gl.SCISSOR_TEST ); + + } + + } + + // texture + + function activeTexture( webglSlot ) { + + if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1; + + if ( currentTextureSlot !== webglSlot ) { + + gl.activeTexture( webglSlot ); + currentTextureSlot = webglSlot; + + } + + } + + function bindTexture( webglType, webglTexture ) { + + if ( currentTextureSlot === null ) { + + activeTexture(); + + } + + var boundTexture = currentBoundTextures[ currentTextureSlot ]; + + if ( boundTexture === undefined ) { + + boundTexture = { type: undefined, texture: undefined }; + currentBoundTextures[ currentTextureSlot ] = boundTexture; + + } + + if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) { + + gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] ); + + boundTexture.type = webglType; + boundTexture.texture = webglTexture; + + } + + } + + function compressedTexImage2D() { + + try { + + gl.compressedTexImage2D.apply( gl, arguments ); + + } catch ( error ) { + + console.error( error ); + + } + + } + + function texImage2D() { + + try { + + gl.texImage2D.apply( gl, arguments ); + + } catch ( error ) { + + console.error( error ); + + } + + } + + // + + function scissor( scissor ) { + + if ( currentScissor.equals( scissor ) === false ) { + + gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w ); + currentScissor.copy( scissor ); + + } + + } + + function viewport( viewport ) { + + if ( currentViewport.equals( viewport ) === false ) { + + gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w ); + currentViewport.copy( viewport ); + + } + + } + + // + + function reset() { + + for ( var i = 0; i < enabledAttributes.length; i ++ ) { + + if ( enabledAttributes[ i ] === 1 ) { + + gl.disableVertexAttribArray( i ); + enabledAttributes[ i ] = 0; + + } + + } + + capabilities = {}; + + compressedTextureFormats = null; + + currentTextureSlot = null; + currentBoundTextures = {}; + + currentBlending = null; + + currentFlipSided = null; + currentCullFace = null; + + colorBuffer.reset(); + depthBuffer.reset(); + stencilBuffer.reset(); + + } + + return { + + buffers: { + color: colorBuffer, + depth: depthBuffer, + stencil: stencilBuffer + }, + + init: init, + initAttributes: initAttributes, + enableAttribute: enableAttribute, + enableAttributeAndDivisor: enableAttributeAndDivisor, + disableUnusedAttributes: disableUnusedAttributes, + enable: enable, + disable: disable, + getCompressedTextureFormats: getCompressedTextureFormats, + + setBlending: setBlending, + + setColorWrite: setColorWrite, + setDepthTest: setDepthTest, + setDepthWrite: setDepthWrite, + setDepthFunc: setDepthFunc, + setStencilTest: setStencilTest, + setStencilWrite: setStencilWrite, + setStencilFunc: setStencilFunc, + setStencilOp: setStencilOp, + + setFlipSided: setFlipSided, + setCullFace: setCullFace, + + setLineWidth: setLineWidth, + setPolygonOffset: setPolygonOffset, + + getScissorTest: getScissorTest, + setScissorTest: setScissorTest, + + activeTexture: activeTexture, + bindTexture: bindTexture, + compressedTexImage2D: compressedTexImage2D, + texImage2D: texImage2D, + + scissor: scissor, + viewport: viewport, + + reset: reset + + }; + +} + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function WebGLCapabilities( gl, extensions, parameters ) { + + var maxAnisotropy; + + function getMaxAnisotropy() { + + if ( maxAnisotropy !== undefined ) return maxAnisotropy; + + var extension = extensions.get( 'EXT_texture_filter_anisotropic' ); + + if ( extension !== null ) { + + maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ); + + } else { + + maxAnisotropy = 0; + + } + + return maxAnisotropy; + + } + + function getMaxPrecision( precision ) { + + if ( precision === 'highp' ) { + + if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 && + gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) { + + return 'highp'; + + } + + precision = 'mediump'; + + } + + if ( precision === 'mediump' ) { + + if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 && + gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) { + + return 'mediump'; + + } + + } + + return 'lowp'; + + } + + var precision = parameters.precision !== undefined ? parameters.precision : 'highp'; + var maxPrecision = getMaxPrecision( precision ); + + if ( maxPrecision !== precision ) { + + console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' ); + precision = maxPrecision; + + } + + var logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true && !! extensions.get( 'EXT_frag_depth' ); + + var maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); + var maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); + var maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE ); + var maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE ); + + var maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); + var maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS ); + var maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS ); + var maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS ); + + var vertexTextures = maxVertexTextures > 0; + var floatFragmentTextures = !! extensions.get( 'OES_texture_float' ); + var floatVertexTextures = vertexTextures && floatFragmentTextures; + + return { + + getMaxAnisotropy: getMaxAnisotropy, + getMaxPrecision: getMaxPrecision, + + precision: precision, + logarithmicDepthBuffer: logarithmicDepthBuffer, + + maxTextures: maxTextures, + maxVertexTextures: maxVertexTextures, + maxTextureSize: maxTextureSize, + maxCubemapSize: maxCubemapSize, + + maxAttributes: maxAttributes, + maxVertexUniforms: maxVertexUniforms, + maxVaryings: maxVaryings, + maxFragmentUniforms: maxFragmentUniforms, + + vertexTextures: vertexTextures, + floatFragmentTextures: floatFragmentTextures, + floatVertexTextures: floatVertexTextures + + }; + +} + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function WebGLExtensions( gl ) { + + var extensions = {}; + + return { + + get: function ( name ) { + + if ( extensions[ name ] !== undefined ) { + + return extensions[ name ]; + + } + + var extension; + + switch ( name ) { + + case 'WEBGL_depth_texture': + extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' ); + break; + + case 'EXT_texture_filter_anisotropic': + extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); + break; + + case 'WEBGL_compressed_texture_s3tc': + extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); + break; + + case 'WEBGL_compressed_texture_pvrtc': + extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); + break; + + case 'WEBGL_compressed_texture_etc1': + extension = gl.getExtension( 'WEBGL_compressed_texture_etc1' ); + break; + + default: + extension = gl.getExtension( name ); + + } + + if ( extension === null ) { + + console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); + + } + + extensions[ name ] = extension; + + return extension; + + } + + }; + +} + +/** + * @author tschw + */ + +function WebGLClipping() { + + var scope = this, + + globalState = null, + numGlobalPlanes = 0, + localClippingEnabled = false, + renderingShadows = false, + + plane = new Plane(), + viewNormalMatrix = new Matrix3(), + + uniform = { value: null, needsUpdate: false }; + + this.uniform = uniform; + this.numPlanes = 0; + this.numIntersection = 0; + + this.init = function( planes, enableLocalClipping, camera ) { + + var enabled = + planes.length !== 0 || + enableLocalClipping || + // enable state of previous frame - the clipping code has to + // run another frame in order to reset the state: + numGlobalPlanes !== 0 || + localClippingEnabled; + + localClippingEnabled = enableLocalClipping; + + globalState = projectPlanes( planes, camera, 0 ); + numGlobalPlanes = planes.length; + + return enabled; + + }; + + this.beginShadows = function() { + + renderingShadows = true; + projectPlanes( null ); + + }; + + this.endShadows = function() { + + renderingShadows = false; + resetGlobalState(); + + }; + + this.setState = function( planes, clipIntersection, clipShadows, camera, cache, fromCache ) { + + if ( ! localClippingEnabled || + planes === null || planes.length === 0 || + renderingShadows && ! clipShadows ) { + // there's no local clipping + + if ( renderingShadows ) { + // there's no global clipping + + projectPlanes( null ); + + } else { + + resetGlobalState(); + } + + } else { + + var nGlobal = renderingShadows ? 0 : numGlobalPlanes, + lGlobal = nGlobal * 4, + + dstArray = cache.clippingState || null; + + uniform.value = dstArray; // ensure unique state + + dstArray = projectPlanes( planes, camera, lGlobal, fromCache ); + + for ( var i = 0; i !== lGlobal; ++ i ) { + + dstArray[ i ] = globalState[ i ]; + + } + + cache.clippingState = dstArray; + this.numIntersection = clipIntersection ? this.numPlanes : 0; + this.numPlanes += nGlobal; + + } + + + }; + + function resetGlobalState() { + + if ( uniform.value !== globalState ) { + + uniform.value = globalState; + uniform.needsUpdate = numGlobalPlanes > 0; + + } + + scope.numPlanes = numGlobalPlanes; + scope.numIntersection = 0; + + } + + function projectPlanes( planes, camera, dstOffset, skipTransform ) { + + var nPlanes = planes !== null ? planes.length : 0, + dstArray = null; + + if ( nPlanes !== 0 ) { + + dstArray = uniform.value; + + if ( skipTransform !== true || dstArray === null ) { + + var flatSize = dstOffset + nPlanes * 4, + viewMatrix = camera.matrixWorldInverse; + + viewNormalMatrix.getNormalMatrix( viewMatrix ); + + if ( dstArray === null || dstArray.length < flatSize ) { + + dstArray = new Float32Array( flatSize ); + + } + + for ( var i = 0, i4 = dstOffset; + i !== nPlanes; ++ i, i4 += 4 ) { + + plane.copy( planes[ i ] ). + applyMatrix4( viewMatrix, viewNormalMatrix ); + + plane.normal.toArray( dstArray, i4 ); + dstArray[ i4 + 3 ] = plane.constant; + + } + + } + + uniform.value = dstArray; + uniform.needsUpdate = true; + + } + + scope.numPlanes = nPlanes; + + return dstArray; + + } + +} + +/** + * @author supereggbert / http://www.paulbrunt.co.uk/ + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author szimek / https://github.com/szimek/ + * @author tschw + */ + +function WebGLRenderer( parameters ) { + + console.log( 'THREE.WebGLRenderer', REVISION ); + + parameters = parameters || {}; + + var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ), + _context = parameters.context !== undefined ? parameters.context : null, + + _alpha = parameters.alpha !== undefined ? parameters.alpha : false, + _depth = parameters.depth !== undefined ? parameters.depth : true, + _stencil = parameters.stencil !== undefined ? parameters.stencil : true, + _antialias = parameters.antialias !== undefined ? parameters.antialias : false, + _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, + _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false; + + var lights = []; + + var opaqueObjects = []; + var opaqueObjectsLastIndex = - 1; + var transparentObjects = []; + var transparentObjectsLastIndex = - 1; + + var morphInfluences = new Float32Array( 8 ); + + var sprites = []; + var lensFlares = []; + + // public properties + + this.domElement = _canvas; + this.context = null; + + // clearing + + this.autoClear = true; + this.autoClearColor = true; + this.autoClearDepth = true; + this.autoClearStencil = true; + + // scene graph + + this.sortObjects = true; + + // user-defined clipping + + this.clippingPlanes = []; + this.localClippingEnabled = false; + + // physically based shading + + this.gammaFactor = 2.0; // for backwards compatibility + this.gammaInput = false; + this.gammaOutput = false; + + // physical lights + + this.physicallyCorrectLights = false; + + // tone mapping + + this.toneMapping = LinearToneMapping; + this.toneMappingExposure = 1.0; + this.toneMappingWhitePoint = 1.0; + + // morphs + + this.maxMorphTargets = 8; + this.maxMorphNormals = 4; + + // internal properties + + var _this = this, + + // internal state cache + + _currentProgram = null, + _currentRenderTarget = null, + _currentFramebuffer = null, + _currentMaterialId = - 1, + _currentGeometryProgram = '', + _currentCamera = null, + + _currentScissor = new Vector4(), + _currentScissorTest = null, + + _currentViewport = new Vector4(), + + // + + _usedTextureUnits = 0, + + // + + _clearColor = new Color( 0x000000 ), + _clearAlpha = 0, + + _width = _canvas.width, + _height = _canvas.height, + + _pixelRatio = 1, + + _scissor = new Vector4( 0, 0, _width, _height ), + _scissorTest = false, + + _viewport = new Vector4( 0, 0, _width, _height ), + + // frustum + + _frustum = new Frustum(), + + // clipping + + _clipping = new WebGLClipping(), + _clippingEnabled = false, + _localClippingEnabled = false, + + _sphere = new Sphere(), + + // camera matrices cache + + _projScreenMatrix = new Matrix4(), + + _vector3 = new Vector3(), + _matrix4 = new Matrix4(), + _matrix42 = new Matrix4(), + + // light arrays cache + + _lights = { + + hash: '', + + ambient: [ 0, 0, 0 ], + directional: [], + directionalShadowMap: [], + directionalShadowMatrix: [], + spot: [], + spotShadowMap: [], + spotShadowMatrix: [], + rectArea: [], + point: [], + pointShadowMap: [], + pointShadowMatrix: [], + hemi: [], + + shadows: [] + + }, + + // info + + _infoRender = { + + calls: 0, + vertices: 0, + faces: 0, + points: 0 + + }; + + this.info = { + + render: _infoRender, + memory: { + + geometries: 0, + textures: 0 + + }, + programs: null + + }; + + + // initialize + + var _gl; + + try { + + var attributes = { + alpha: _alpha, + depth: _depth, + stencil: _stencil, + antialias: _antialias, + premultipliedAlpha: _premultipliedAlpha, + preserveDrawingBuffer: _preserveDrawingBuffer + }; + + _gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes ); + + if ( _gl === null ) { + + if ( _canvas.getContext( 'webgl' ) !== null ) { + + throw 'Error creating WebGL context with your selected attributes.'; + + } else { + + throw 'Error creating WebGL context.'; + + } + + } + + // Some experimental-webgl implementations do not have getShaderPrecisionFormat + + if ( _gl.getShaderPrecisionFormat === undefined ) { + + _gl.getShaderPrecisionFormat = function () { + + return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; + + }; + + } + + _canvas.addEventListener( 'webglcontextlost', onContextLost, false ); + + } catch ( error ) { + + console.error( 'THREE.WebGLRenderer: ' + error ); + + } + + var extensions = new WebGLExtensions( _gl ); + + extensions.get( 'WEBGL_depth_texture' ); + extensions.get( 'OES_texture_float' ); + extensions.get( 'OES_texture_float_linear' ); + extensions.get( 'OES_texture_half_float' ); + extensions.get( 'OES_texture_half_float_linear' ); + extensions.get( 'OES_standard_derivatives' ); + extensions.get( 'ANGLE_instanced_arrays' ); + + if ( extensions.get( 'OES_element_index_uint' ) ) { + + BufferGeometry.MaxIndex = 4294967296; + + } + + var capabilities = new WebGLCapabilities( _gl, extensions, parameters ); + + var state = new WebGLState( _gl, extensions, paramThreeToGL ); + var properties = new WebGLProperties(); + var textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, this.info ); + var objects = new WebGLObjects( _gl, properties, this.info ); + var programCache = new WebGLPrograms( this, capabilities ); + var lightCache = new WebGLLights(); + + this.info.programs = programCache.programs; + + var bufferRenderer = new WebGLBufferRenderer( _gl, extensions, _infoRender ); + var indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, _infoRender ); + + // + + var backgroundPlaneCamera, backgroundPlaneMesh; + var backgroundBoxCamera, backgroundBoxMesh; + + // + + function getTargetPixelRatio() { + + return _currentRenderTarget === null ? _pixelRatio : 1; + + } + + function setDefaultGLState() { + + state.init(); + + state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) ); + state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) ); + + state.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha ); + + } + + function resetGLState() { + + _currentProgram = null; + _currentCamera = null; + + _currentGeometryProgram = ''; + _currentMaterialId = - 1; + + state.reset(); + + } + + setDefaultGLState(); + + this.context = _gl; + this.capabilities = capabilities; + this.extensions = extensions; + this.properties = properties; + this.state = state; + + // shadow map + + var shadowMap = new WebGLShadowMap( this, _lights, objects, capabilities ); + + this.shadowMap = shadowMap; + + + // Plugins + + var spritePlugin = new SpritePlugin( this, sprites ); + var lensFlarePlugin = new LensFlarePlugin( this, lensFlares ); + + // API + + this.getContext = function () { + + return _gl; + + }; + + this.getContextAttributes = function () { + + return _gl.getContextAttributes(); + + }; + + this.forceContextLoss = function () { + + extensions.get( 'WEBGL_lose_context' ).loseContext(); + + }; + + this.getMaxAnisotropy = function () { + + return capabilities.getMaxAnisotropy(); + + }; + + this.getPrecision = function () { + + return capabilities.precision; + + }; + + this.getPixelRatio = function () { + + return _pixelRatio; + + }; + + this.setPixelRatio = function ( value ) { + + if ( value === undefined ) return; + + _pixelRatio = value; + + this.setSize( _viewport.z, _viewport.w, false ); + + }; + + this.getSize = function () { + + return { + width: _width, + height: _height + }; + + }; + + this.setSize = function ( width, height, updateStyle ) { + + _width = width; + _height = height; + + _canvas.width = width * _pixelRatio; + _canvas.height = height * _pixelRatio; + + if ( updateStyle !== false ) { + + _canvas.style.width = width + 'px'; + _canvas.style.height = height + 'px'; + + } + + this.setViewport( 0, 0, width, height ); + + }; + + this.setViewport = function ( x, y, width, height ) { + + state.viewport( _viewport.set( x, y, width, height ) ); + + }; + + this.setScissor = function ( x, y, width, height ) { + + state.scissor( _scissor.set( x, y, width, height ) ); + + }; + + this.setScissorTest = function ( boolean ) { + + state.setScissorTest( _scissorTest = boolean ); + + }; + + // Clearing + + this.getClearColor = function () { + + return _clearColor; + + }; + + this.setClearColor = function ( color, alpha ) { + + _clearColor.set( color ); + + _clearAlpha = alpha !== undefined ? alpha : 1; + + state.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha ); + + }; + + this.getClearAlpha = function () { + + return _clearAlpha; + + }; + + this.setClearAlpha = function ( alpha ) { + + _clearAlpha = alpha; + + state.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha ); + + }; + + this.clear = function ( color, depth, stencil ) { + + var bits = 0; + + if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT; + if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT; + if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT; + + _gl.clear( bits ); + + }; + + this.clearColor = function () { + + this.clear( true, false, false ); + + }; + + this.clearDepth = function () { + + this.clear( false, true, false ); + + }; + + this.clearStencil = function () { + + this.clear( false, false, true ); + + }; + + this.clearTarget = function ( renderTarget, color, depth, stencil ) { + + this.setRenderTarget( renderTarget ); + this.clear( color, depth, stencil ); + + }; + + // Reset + + this.resetGLState = resetGLState; + + this.dispose = function() { + + transparentObjects = []; + transparentObjectsLastIndex = -1; + opaqueObjects = []; + opaqueObjectsLastIndex = -1; + + _canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); + + }; + + // Events + + function onContextLost( event ) { + + event.preventDefault(); + + resetGLState(); + setDefaultGLState(); + + properties.clear(); + + } + + function onMaterialDispose( event ) { + + var material = event.target; + + material.removeEventListener( 'dispose', onMaterialDispose ); + + deallocateMaterial( material ); + + } + + // Buffer deallocation + + function deallocateMaterial( material ) { + + releaseMaterialProgramReference( material ); + + properties.delete( material ); + + } + + + function releaseMaterialProgramReference( material ) { + + var programInfo = properties.get( material ).program; + + material.program = undefined; + + if ( programInfo !== undefined ) { + + programCache.releaseProgram( programInfo ); + + } + + } + + // Buffer rendering + + this.renderBufferImmediate = function ( object, program, material ) { + + state.initAttributes(); + + var buffers = properties.get( object ); + + if ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer(); + if ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer(); + if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer(); + if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer(); + + var attributes = program.getAttributes(); + + if ( object.hasPositions ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.position ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); + + state.enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + + } + + if ( object.hasNormals ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.normal ); + + if ( ! material.isMeshPhongMaterial && + ! material.isMeshStandardMaterial && + ! material.isMeshNormalMaterial && + material.shading === FlatShading ) { + + for ( var i = 0, l = object.count * 3; i < l; i += 9 ) { + + var array = object.normalArray; + + var nx = ( array[ i + 0 ] + array[ i + 3 ] + array[ i + 6 ] ) / 3; + var ny = ( array[ i + 1 ] + array[ i + 4 ] + array[ i + 7 ] ) / 3; + var nz = ( array[ i + 2 ] + array[ i + 5 ] + array[ i + 8 ] ) / 3; + + array[ i + 0 ] = nx; + array[ i + 1 ] = ny; + array[ i + 2 ] = nz; + + array[ i + 3 ] = nx; + array[ i + 4 ] = ny; + array[ i + 5 ] = nz; + + array[ i + 6 ] = nx; + array[ i + 7 ] = ny; + array[ i + 8 ] = nz; + + } + + } + + _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); + + state.enableAttribute( attributes.normal ); + + _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); + + } + + if ( object.hasUvs && material.map ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.uv ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); + + state.enableAttribute( attributes.uv ); + + _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); + + } + + if ( object.hasColors && material.vertexColors !== NoColors ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.color ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); + + state.enableAttribute( attributes.color ); + + _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); + + } + + state.disableUnusedAttributes(); + + _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); + + object.count = 0; + + }; + + this.renderBufferDirect = function ( camera, fog, geometry, material, object, group ) { + + setMaterial( material ); + + var program = setProgram( camera, fog, material, object ); + + var updateBuffers = false; + var geometryProgram = geometry.id + '_' + program.id + '_' + material.wireframe; + + if ( geometryProgram !== _currentGeometryProgram ) { + + _currentGeometryProgram = geometryProgram; + updateBuffers = true; + + } + + // morph targets + + var morphTargetInfluences = object.morphTargetInfluences; + + if ( morphTargetInfluences !== undefined ) { + + var activeInfluences = []; + + for ( var i = 0, l = morphTargetInfluences.length; i < l; i ++ ) { + + var influence = morphTargetInfluences[ i ]; + activeInfluences.push( [ influence, i ] ); + + } + + activeInfluences.sort( absNumericalSort ); + + if ( activeInfluences.length > 8 ) { + + activeInfluences.length = 8; + + } + + var morphAttributes = geometry.morphAttributes; + + for ( var i = 0, l = activeInfluences.length; i < l; i ++ ) { + + var influence = activeInfluences[ i ]; + morphInfluences[ i ] = influence[ 0 ]; + + if ( influence[ 0 ] !== 0 ) { + + var index = influence[ 1 ]; + + if ( material.morphTargets === true && morphAttributes.position ) geometry.addAttribute( 'morphTarget' + i, morphAttributes.position[ index ] ); + if ( material.morphNormals === true && morphAttributes.normal ) geometry.addAttribute( 'morphNormal' + i, morphAttributes.normal[ index ] ); + + } else { + + if ( material.morphTargets === true ) geometry.removeAttribute( 'morphTarget' + i ); + if ( material.morphNormals === true ) geometry.removeAttribute( 'morphNormal' + i ); + + } + + } + + for ( var i = activeInfluences.length, il = morphInfluences.length; i < il; i ++ ) { + + morphInfluences[ i ] = 0.0; + + } + + program.getUniforms().setValue( + _gl, 'morphTargetInfluences', morphInfluences ); + + updateBuffers = true; + + } + + // + + var index = geometry.index; + var position = geometry.attributes.position; + var rangeFactor = 1; + + if ( material.wireframe === true ) { + + index = objects.getWireframeAttribute( geometry ); + rangeFactor = 2; + + } + + var renderer; + + if ( index !== null ) { + + renderer = indexedBufferRenderer; + renderer.setIndex( index ); + + } else { + + renderer = bufferRenderer; + + } + + if ( updateBuffers ) { + + setupVertexAttributes( material, program, geometry ); + + if ( index !== null ) { + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, objects.getAttributeBuffer( index ) ); + + } + + } + + // + + var dataCount = 0; + + if ( index !== null ) { + + dataCount = index.count; + + } else if ( position !== undefined ) { + + dataCount = position.count; + + } + + var rangeStart = geometry.drawRange.start * rangeFactor; + var rangeCount = geometry.drawRange.count * rangeFactor; + + var groupStart = group !== null ? group.start * rangeFactor : 0; + var groupCount = group !== null ? group.count * rangeFactor : Infinity; + + var drawStart = Math.max( rangeStart, groupStart ); + var drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1; + + var drawCount = Math.max( 0, drawEnd - drawStart + 1 ); + + if ( drawCount === 0 ) return; + + // + + if ( object.isMesh ) { + + if ( material.wireframe === true ) { + + state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); + renderer.setMode( _gl.LINES ); + + } else { + + switch ( object.drawMode ) { + + case TrianglesDrawMode: + renderer.setMode( _gl.TRIANGLES ); + break; + + case TriangleStripDrawMode: + renderer.setMode( _gl.TRIANGLE_STRIP ); + break; + + case TriangleFanDrawMode: + renderer.setMode( _gl.TRIANGLE_FAN ); + break; + + } + + } + + + } else if ( object.isLine ) { + + var lineWidth = material.linewidth; + + if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material + + state.setLineWidth( lineWidth * getTargetPixelRatio() ); + + if ( object.isLineSegments ) { + + renderer.setMode( _gl.LINES ); + + } else { + + renderer.setMode( _gl.LINE_STRIP ); + + } + + } else if ( object.isPoints ) { + + renderer.setMode( _gl.POINTS ); + + } + + if ( geometry && geometry.isInstancedBufferGeometry ) { + + if ( geometry.maxInstancedCount > 0 ) { + + renderer.renderInstances( geometry, drawStart, drawCount ); + + } + + } else { + + renderer.render( drawStart, drawCount ); + + } + + }; + + function setupVertexAttributes( material, program, geometry, startIndex ) { + + var extension; + + if ( geometry && geometry.isInstancedBufferGeometry ) { + + extension = extensions.get( 'ANGLE_instanced_arrays' ); + + if ( extension === null ) { + + console.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); + return; + + } + + } + + if ( startIndex === undefined ) startIndex = 0; + + state.initAttributes(); + + var geometryAttributes = geometry.attributes; + + var programAttributes = program.getAttributes(); + + var materialDefaultAttributeValues = material.defaultAttributeValues; + + for ( var name in programAttributes ) { + + var programAttribute = programAttributes[ name ]; + + if ( programAttribute >= 0 ) { + + var geometryAttribute = geometryAttributes[ name ]; + + if ( geometryAttribute !== undefined ) { + + var normalized = geometryAttribute.normalized; + var size = geometryAttribute.itemSize; + + var attributeProperties = objects.getAttributeProperties( geometryAttribute ); + + var buffer = attributeProperties.__webglBuffer; + var type = attributeProperties.type; + var bytesPerElement = attributeProperties.bytesPerElement; + + if ( geometryAttribute.isInterleavedBufferAttribute ) { + + var data = geometryAttribute.data; + var stride = data.stride; + var offset = geometryAttribute.offset; + + if ( data && data.isInstancedInterleavedBuffer ) { + + state.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute, extension ); + + if ( geometry.maxInstancedCount === undefined ) { + + geometry.maxInstancedCount = data.meshPerAttribute * data.count; + + } + + } else { + + state.enableAttribute( programAttribute ); + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer ); + _gl.vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, ( startIndex * stride + offset ) * bytesPerElement ); + + } else { + + if ( geometryAttribute.isInstancedBufferAttribute ) { + + state.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute, extension ); + + if ( geometry.maxInstancedCount === undefined ) { + + geometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; + + } + + } else { + + state.enableAttribute( programAttribute ); + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer ); + _gl.vertexAttribPointer( programAttribute, size, type, normalized, 0, startIndex * size * bytesPerElement ); + + } + + } else if ( materialDefaultAttributeValues !== undefined ) { + + var value = materialDefaultAttributeValues[ name ]; + + if ( value !== undefined ) { + + switch ( value.length ) { + + case 2: + _gl.vertexAttrib2fv( programAttribute, value ); + break; + + case 3: + _gl.vertexAttrib3fv( programAttribute, value ); + break; + + case 4: + _gl.vertexAttrib4fv( programAttribute, value ); + break; + + default: + _gl.vertexAttrib1fv( programAttribute, value ); + + } + + } + + } + + } + + } + + state.disableUnusedAttributes(); + + } + + // Sorting + + function absNumericalSort( a, b ) { + + return Math.abs( b[ 0 ] ) - Math.abs( a[ 0 ] ); + + } + + function painterSortStable( a, b ) { + + if ( a.object.renderOrder !== b.object.renderOrder ) { + + return a.object.renderOrder - b.object.renderOrder; + + } else if ( a.material.program && b.material.program && a.material.program !== b.material.program ) { + + return a.material.program.id - b.material.program.id; + + } else if ( a.material.id !== b.material.id ) { + + return a.material.id - b.material.id; + + } else if ( a.z !== b.z ) { + + return a.z - b.z; + + } else { + + return a.id - b.id; + + } + + } + + function reversePainterSortStable( a, b ) { + + if ( a.object.renderOrder !== b.object.renderOrder ) { + + return a.object.renderOrder - b.object.renderOrder; + + } if ( a.z !== b.z ) { + + return b.z - a.z; + + } else { + + return a.id - b.id; + + } + + } + + // Rendering + + this.render = function ( scene, camera, renderTarget, forceClear ) { + + if ( camera !== undefined && camera.isCamera !== true ) { + + console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); + return; + + } + + // reset caching for this frame + + _currentGeometryProgram = ''; + _currentMaterialId = - 1; + _currentCamera = null; + + // update scene graph + + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); + + // update camera matrices and frustum + + if ( camera.parent === null ) camera.updateMatrixWorld(); + + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); + + lights.length = 0; + + opaqueObjectsLastIndex = - 1; + transparentObjectsLastIndex = - 1; + + sprites.length = 0; + lensFlares.length = 0; + + _localClippingEnabled = this.localClippingEnabled; + _clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera ); + + projectObject( scene, camera ); + + opaqueObjects.length = opaqueObjectsLastIndex + 1; + transparentObjects.length = transparentObjectsLastIndex + 1; + + if ( _this.sortObjects === true ) { + + opaqueObjects.sort( painterSortStable ); + transparentObjects.sort( reversePainterSortStable ); + + } + + // + + if ( _clippingEnabled ) _clipping.beginShadows(); + + setupShadows( lights ); + + shadowMap.render( scene, camera ); + + setupLights( lights, camera ); + + if ( _clippingEnabled ) _clipping.endShadows(); + + // + + _infoRender.calls = 0; + _infoRender.vertices = 0; + _infoRender.faces = 0; + _infoRender.points = 0; + + if ( renderTarget === undefined ) { + + renderTarget = null; + + } + + this.setRenderTarget( renderTarget ); + + // + + var background = scene.background; + + if ( background === null ) { + + state.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha ); + + } else if ( background && background.isColor ) { + + state.buffers.color.setClear( background.r, background.g, background.b, 1, _premultipliedAlpha ); + forceClear = true; + + } + + if ( this.autoClear || forceClear ) { + + this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil ); + + } + + if ( background && background.isCubeTexture ) { + + if ( backgroundBoxCamera === undefined ) { + + backgroundBoxCamera = new PerspectiveCamera(); + + backgroundBoxMesh = new Mesh( + new BoxBufferGeometry( 5, 5, 5 ), + new ShaderMaterial( { + uniforms: ShaderLib.cube.uniforms, + vertexShader: ShaderLib.cube.vertexShader, + fragmentShader: ShaderLib.cube.fragmentShader, + side: BackSide, + depthTest: false, + depthWrite: false, + fog: false + } ) + ); + + } + + backgroundBoxCamera.projectionMatrix.copy( camera.projectionMatrix ); + + backgroundBoxCamera.matrixWorld.extractRotation( camera.matrixWorld ); + backgroundBoxCamera.matrixWorldInverse.getInverse( backgroundBoxCamera.matrixWorld ); + + + backgroundBoxMesh.material.uniforms[ "tCube" ].value = background; + backgroundBoxMesh.modelViewMatrix.multiplyMatrices( backgroundBoxCamera.matrixWorldInverse, backgroundBoxMesh.matrixWorld ); + + objects.update( backgroundBoxMesh ); + + _this.renderBufferDirect( backgroundBoxCamera, null, backgroundBoxMesh.geometry, backgroundBoxMesh.material, backgroundBoxMesh, null ); + + } else if ( background && background.isTexture ) { + + if ( backgroundPlaneCamera === undefined ) { + + backgroundPlaneCamera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); + + backgroundPlaneMesh = new Mesh( + new PlaneBufferGeometry( 2, 2 ), + new MeshBasicMaterial( { depthTest: false, depthWrite: false, fog: false } ) + ); + + } + + backgroundPlaneMesh.material.map = background; + + objects.update( backgroundPlaneMesh ); + + _this.renderBufferDirect( backgroundPlaneCamera, null, backgroundPlaneMesh.geometry, backgroundPlaneMesh.material, backgroundPlaneMesh, null ); + + } + + // + + if ( scene.overrideMaterial ) { + + var overrideMaterial = scene.overrideMaterial; + + renderObjects( opaqueObjects, scene, camera, overrideMaterial ); + renderObjects( transparentObjects, scene, camera, overrideMaterial ); + + } else { + + // opaque pass (front-to-back order) + + state.setBlending( NoBlending ); + renderObjects( opaqueObjects, scene, camera ); + + // transparent pass (back-to-front order) + + renderObjects( transparentObjects, scene, camera ); + + } + + // custom render plugins (post pass) + + spritePlugin.render( scene, camera ); + lensFlarePlugin.render( scene, camera, _currentViewport ); + + // Generate mipmap if we're using any kind of mipmap filtering + + if ( renderTarget ) { + + textures.updateRenderTargetMipmap( renderTarget ); + + } + + // Ensure depth buffer writing is enabled so it can be cleared on next render + + state.setDepthTest( true ); + state.setDepthWrite( true ); + state.setColorWrite( true ); + + // _gl.finish(); + + }; + + function pushRenderItem( object, geometry, material, z, group ) { + + var array, index; + + // allocate the next position in the appropriate array + + if ( material.transparent ) { + + array = transparentObjects; + index = ++ transparentObjectsLastIndex; + + } else { + + array = opaqueObjects; + index = ++ opaqueObjectsLastIndex; + + } + + // recycle existing render item or grow the array + + var renderItem = array[ index ]; + + if ( renderItem !== undefined ) { + + renderItem.id = object.id; + renderItem.object = object; + renderItem.geometry = geometry; + renderItem.material = material; + renderItem.z = _vector3.z; + renderItem.group = group; + + } else { + + renderItem = { + id: object.id, + object: object, + geometry: geometry, + material: material, + z: _vector3.z, + group: group + }; + + // assert( index === array.length ); + array.push( renderItem ); + + } + + } + + // TODO Duplicated code (Frustum) + + function isObjectViewable( object ) { + + var geometry = object.geometry; + + if ( geometry.boundingSphere === null ) + geometry.computeBoundingSphere(); + + _sphere.copy( geometry.boundingSphere ). + applyMatrix4( object.matrixWorld ); + + return isSphereViewable( _sphere ); + + } + + function isSpriteViewable( sprite ) { + + _sphere.center.set( 0, 0, 0 ); + _sphere.radius = 0.7071067811865476; + _sphere.applyMatrix4( sprite.matrixWorld ); + + return isSphereViewable( _sphere ); + + } + + function isSphereViewable( sphere ) { + + if ( ! _frustum.intersectsSphere( sphere ) ) return false; + + var numPlanes = _clipping.numPlanes; + + if ( numPlanes === 0 ) return true; + + var planes = _this.clippingPlanes, + + center = sphere.center, + negRad = - sphere.radius, + i = 0; + + do { + + // out when deeper than radius in the negative halfspace + if ( planes[ i ].distanceToPoint( center ) < negRad ) return false; + + } while ( ++ i !== numPlanes ); + + return true; + + } + + function projectObject( object, camera ) { + + if ( object.visible === false ) return; + + var visible = ( object.layers.mask & camera.layers.mask ) !== 0; + + if ( visible ) { + + if ( object.isLight ) { + + lights.push( object ); + + } else if ( object.isSprite ) { + + if ( object.frustumCulled === false || isSpriteViewable( object ) === true ) { + + sprites.push( object ); + + } + + } else if ( object.isLensFlare ) { + + lensFlares.push( object ); + + } else if ( object.isImmediateRenderObject ) { + + if ( _this.sortObjects === true ) { + + _vector3.setFromMatrixPosition( object.matrixWorld ); + _vector3.applyMatrix4( _projScreenMatrix ); + + } + + pushRenderItem( object, null, object.material, _vector3.z, null ); + + } else if ( object.isMesh || object.isLine || object.isPoints ) { + + if ( object.isSkinnedMesh ) { + + object.skeleton.update(); + + } + + if ( object.frustumCulled === false || isObjectViewable( object ) === true ) { + + var material = object.material; + + if ( material.visible === true ) { + + if ( _this.sortObjects === true ) { + + _vector3.setFromMatrixPosition( object.matrixWorld ); + _vector3.applyMatrix4( _projScreenMatrix ); + + } + + var geometry = objects.update( object ); + + if ( material.isMultiMaterial ) { + + var groups = geometry.groups; + var materials = material.materials; + + for ( var i = 0, l = groups.length; i < l; i ++ ) { + + var group = groups[ i ]; + var groupMaterial = materials[ group.materialIndex ]; + + if ( groupMaterial.visible === true ) { + + pushRenderItem( object, geometry, groupMaterial, _vector3.z, group ); + + } + + } + + } else { + + pushRenderItem( object, geometry, material, _vector3.z, null ); + + } + + } + + } + + } + + } + + var children = object.children; + + for ( var i = 0, l = children.length; i < l; i ++ ) { + + projectObject( children[ i ], camera ); + + } + + } + + function renderObjects( renderList, scene, camera, overrideMaterial ) { + + for ( var i = 0, l = renderList.length; i < l; i ++ ) { + + var renderItem = renderList[ i ]; + + var object = renderItem.object; + var geometry = renderItem.geometry; + var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial; + var group = renderItem.group; + + object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); + + object.onBeforeRender( _this, scene, camera, geometry, material, group ); + + if ( object.isImmediateRenderObject ) { + + setMaterial( material ); + + var program = setProgram( camera, scene.fog, material, object ); + + _currentGeometryProgram = ''; + + object.render( function ( object ) { + + _this.renderBufferImmediate( object, program, material ); + + } ); + + } else { + + _this.renderBufferDirect( camera, scene.fog, geometry, material, object, group ); + + } + + object.onAfterRender( _this, scene, camera, geometry, material, group ); + + + } + + } + + function initMaterial( material, fog, object ) { + + var materialProperties = properties.get( material ); + + var parameters = programCache.getParameters( + material, _lights, fog, _clipping.numPlanes, _clipping.numIntersection, object ); + + var code = programCache.getProgramCode( material, parameters ); + + var program = materialProperties.program; + var programChange = true; + + if ( program === undefined ) { + + // new material + material.addEventListener( 'dispose', onMaterialDispose ); + + } else if ( program.code !== code ) { + + // changed glsl or parameters + releaseMaterialProgramReference( material ); + + } else if ( parameters.shaderID !== undefined ) { + + // same glsl and uniform list + return; + + } else { + + // only rebuild uniform list + programChange = false; + + } + + if ( programChange ) { + + if ( parameters.shaderID ) { + + var shader = ShaderLib[ parameters.shaderID ]; + + materialProperties.__webglShader = { + name: material.type, + uniforms: UniformsUtils.clone( shader.uniforms ), + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader + }; + + } else { + + materialProperties.__webglShader = { + name: material.type, + uniforms: material.uniforms, + vertexShader: material.vertexShader, + fragmentShader: material.fragmentShader + }; + + } + + material.__webglShader = materialProperties.__webglShader; + + program = programCache.acquireProgram( material, parameters, code ); + + materialProperties.program = program; + material.program = program; + + } + + var attributes = program.getAttributes(); + + if ( material.morphTargets ) { + + material.numSupportedMorphTargets = 0; + + for ( var i = 0; i < _this.maxMorphTargets; i ++ ) { + + if ( attributes[ 'morphTarget' + i ] >= 0 ) { + + material.numSupportedMorphTargets ++; + + } + + } + + } + + if ( material.morphNormals ) { + + material.numSupportedMorphNormals = 0; + + for ( var i = 0; i < _this.maxMorphNormals; i ++ ) { + + if ( attributes[ 'morphNormal' + i ] >= 0 ) { + + material.numSupportedMorphNormals ++; + + } + + } + + } + + var uniforms = materialProperties.__webglShader.uniforms; + + if ( ! material.isShaderMaterial && + ! material.isRawShaderMaterial || + material.clipping === true ) { + + materialProperties.numClippingPlanes = _clipping.numPlanes; + materialProperties.numIntersection = _clipping.numIntersection; + uniforms.clippingPlanes = _clipping.uniform; + + } + + materialProperties.fog = fog; + + // store the light setup it was created for + + materialProperties.lightsHash = _lights.hash; + + if ( material.lights ) { + + // wire up the material to this renderer's lighting state + + uniforms.ambientLightColor.value = _lights.ambient; + uniforms.directionalLights.value = _lights.directional; + uniforms.spotLights.value = _lights.spot; + uniforms.rectAreaLights.value = _lights.rectArea; + uniforms.pointLights.value = _lights.point; + uniforms.hemisphereLights.value = _lights.hemi; + + uniforms.directionalShadowMap.value = _lights.directionalShadowMap; + uniforms.directionalShadowMatrix.value = _lights.directionalShadowMatrix; + uniforms.spotShadowMap.value = _lights.spotShadowMap; + uniforms.spotShadowMatrix.value = _lights.spotShadowMatrix; + uniforms.pointShadowMap.value = _lights.pointShadowMap; + uniforms.pointShadowMatrix.value = _lights.pointShadowMatrix; + // TODO (abelnation): add area lights shadow info to uniforms + + } + + var progUniforms = materialProperties.program.getUniforms(), + uniformsList = + WebGLUniforms.seqWithValue( progUniforms.seq, uniforms ); + + materialProperties.uniformsList = uniformsList; + + } + + function setMaterial( material ) { + + material.side === DoubleSide + ? state.disable( _gl.CULL_FACE ) + : state.enable( _gl.CULL_FACE ); + + state.setFlipSided( material.side === BackSide ); + + material.transparent === true + ? state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ) + : state.setBlending( NoBlending ); + + state.setDepthFunc( material.depthFunc ); + state.setDepthTest( material.depthTest ); + state.setDepthWrite( material.depthWrite ); + state.setColorWrite( material.colorWrite ); + state.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + + } + + function setProgram( camera, fog, material, object ) { + + _usedTextureUnits = 0; + + var materialProperties = properties.get( material ); + + if ( _clippingEnabled ) { + + if ( _localClippingEnabled || camera !== _currentCamera ) { + + var useCache = + camera === _currentCamera && + material.id === _currentMaterialId; + + // we might want to call this function with some ClippingGroup + // object instead of the material, once it becomes feasible + // (#8465, #8379) + _clipping.setState( + material.clippingPlanes, material.clipIntersection, material.clipShadows, + camera, materialProperties, useCache ); + + } + + } + + if ( material.needsUpdate === false ) { + + if ( materialProperties.program === undefined ) { + + material.needsUpdate = true; + + } else if ( material.fog && materialProperties.fog !== fog ) { + + material.needsUpdate = true; + + } else if ( material.lights && materialProperties.lightsHash !== _lights.hash ) { + + material.needsUpdate = true; + + } else if ( materialProperties.numClippingPlanes !== undefined && + ( materialProperties.numClippingPlanes !== _clipping.numPlanes || + materialProperties.numIntersection !== _clipping.numIntersection ) ) { + + material.needsUpdate = true; + + } + + } + + if ( material.needsUpdate ) { + + initMaterial( material, fog, object ); + material.needsUpdate = false; + + } + + var refreshProgram = false; + var refreshMaterial = false; + var refreshLights = false; + + var program = materialProperties.program, + p_uniforms = program.getUniforms(), + m_uniforms = materialProperties.__webglShader.uniforms; + + if ( program.id !== _currentProgram ) { + + _gl.useProgram( program.program ); + _currentProgram = program.id; + + refreshProgram = true; + refreshMaterial = true; + refreshLights = true; + + } + + if ( material.id !== _currentMaterialId ) { + + _currentMaterialId = material.id; + + refreshMaterial = true; + + } + + if ( refreshProgram || camera !== _currentCamera ) { + + p_uniforms.set( _gl, camera, 'projectionMatrix' ); + + if ( capabilities.logarithmicDepthBuffer ) { + + p_uniforms.setValue( _gl, 'logDepthBufFC', + 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); + + } + + + if ( camera !== _currentCamera ) { + + _currentCamera = camera; + + // lighting uniforms depend on the camera so enforce an update + // now, in case this material supports lights - or later, when + // the next material that does gets activated: + + refreshMaterial = true; // set to true on material change + refreshLights = true; // remains set until update done + + } + + // load material specific uniforms + // (shader material also gets them for the sake of genericity) + + if ( material.isShaderMaterial || + material.isMeshPhongMaterial || + material.isMeshStandardMaterial || + material.envMap ) { + + var uCamPos = p_uniforms.map.cameraPosition; + + if ( uCamPos !== undefined ) { + + uCamPos.setValue( _gl, + _vector3.setFromMatrixPosition( camera.matrixWorld ) ); + + } + + } + + if ( material.isMeshPhongMaterial || + material.isMeshLambertMaterial || + material.isMeshBasicMaterial || + material.isMeshStandardMaterial || + material.isShaderMaterial || + material.skinning ) { + + p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); + + } + + p_uniforms.set( _gl, _this, 'toneMappingExposure' ); + p_uniforms.set( _gl, _this, 'toneMappingWhitePoint' ); + + } + + // skinning uniforms must be set even if material didn't change + // auto-setting of texture unit for bone texture must go before other textures + // not sure why, but otherwise weird things happen + + if ( material.skinning ) { + + p_uniforms.setOptional( _gl, object, 'bindMatrix' ); + p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); + + var skeleton = object.skeleton; + + if ( skeleton ) { + + if ( capabilities.floatVertexTextures && skeleton.useVertexTexture ) { + + p_uniforms.set( _gl, skeleton, 'boneTexture' ); + p_uniforms.set( _gl, skeleton, 'boneTextureWidth' ); + p_uniforms.set( _gl, skeleton, 'boneTextureHeight' ); + + } else { + + p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' ); + + } + + } + + } + + if ( refreshMaterial ) { + + if ( material.lights ) { + + // the current material requires lighting info + + // note: all lighting uniforms are always set correctly + // they simply reference the renderer's state for their + // values + // + // use the current material's .needsUpdate flags to set + // the GL state when required + + markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); + + } + + // refresh uniforms common to several materials + + if ( fog && material.fog ) { + + refreshUniformsFog( m_uniforms, fog ); + + } + + if ( material.isMeshBasicMaterial || + material.isMeshLambertMaterial || + material.isMeshPhongMaterial || + material.isMeshStandardMaterial || + material.isMeshNormalMaterial || + material.isMeshDepthMaterial ) { + + refreshUniformsCommon( m_uniforms, material ); + + } + + // refresh single material specific uniforms + + if ( material.isLineBasicMaterial ) { + + refreshUniformsLine( m_uniforms, material ); + + } else if ( material.isLineDashedMaterial ) { + + refreshUniformsLine( m_uniforms, material ); + refreshUniformsDash( m_uniforms, material ); + + } else if ( material.isPointsMaterial ) { + + refreshUniformsPoints( m_uniforms, material ); + + } else if ( material.isMeshLambertMaterial ) { + + refreshUniformsLambert( m_uniforms, material ); + + } else if ( material.isMeshToonMaterial ) { + + refreshUniformsToon( m_uniforms, material ); + + } else if ( material.isMeshPhongMaterial ) { + + refreshUniformsPhong( m_uniforms, material ); + + } else if ( material.isMeshPhysicalMaterial ) { + + refreshUniformsPhysical( m_uniforms, material ); + + } else if ( material.isMeshStandardMaterial ) { + + refreshUniformsStandard( m_uniforms, material ); + + } else if ( material.isMeshDepthMaterial ) { + + if ( material.displacementMap ) { + + m_uniforms.displacementMap.value = material.displacementMap; + m_uniforms.displacementScale.value = material.displacementScale; + m_uniforms.displacementBias.value = material.displacementBias; + + } + + } else if ( material.isMeshNormalMaterial ) { + + refreshUniformsNormal( m_uniforms, material ); + + } + + // RectAreaLight Texture + // TODO (mrdoob): Find a nicer implementation + + if ( m_uniforms.ltcMat !== undefined ) m_uniforms.ltcMat.value = THREE.UniformsLib.LTC_MAT_TEXTURE; + if ( m_uniforms.ltcMag !== undefined ) m_uniforms.ltcMag.value = THREE.UniformsLib.LTC_MAG_TEXTURE; + + WebGLUniforms.upload( + _gl, materialProperties.uniformsList, m_uniforms, _this ); + + } + + + // common matrices + + p_uniforms.set( _gl, object, 'modelViewMatrix' ); + p_uniforms.set( _gl, object, 'normalMatrix' ); + p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); + + return program; + + } + + // Uniforms (refresh uniforms objects) + + function refreshUniformsCommon( uniforms, material ) { + + uniforms.opacity.value = material.opacity; + + uniforms.diffuse.value = material.color; + + if ( material.emissive ) { + + uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); + + } + + uniforms.map.value = material.map; + uniforms.specularMap.value = material.specularMap; + uniforms.alphaMap.value = material.alphaMap; + + if ( material.lightMap ) { + + uniforms.lightMap.value = material.lightMap; + uniforms.lightMapIntensity.value = material.lightMapIntensity; + + } + + if ( material.aoMap ) { + + uniforms.aoMap.value = material.aoMap; + uniforms.aoMapIntensity.value = material.aoMapIntensity; + + } + + // uv repeat and offset setting priorities + // 1. color map + // 2. specular map + // 3. normal map + // 4. bump map + // 5. alpha map + // 6. emissive map + + var uvScaleMap; + + if ( material.map ) { + + uvScaleMap = material.map; + + } else if ( material.specularMap ) { + + uvScaleMap = material.specularMap; + + } else if ( material.displacementMap ) { + + uvScaleMap = material.displacementMap; + + } else if ( material.normalMap ) { + + uvScaleMap = material.normalMap; + + } else if ( material.bumpMap ) { + + uvScaleMap = material.bumpMap; + + } else if ( material.roughnessMap ) { + + uvScaleMap = material.roughnessMap; + + } else if ( material.metalnessMap ) { + + uvScaleMap = material.metalnessMap; + + } else if ( material.alphaMap ) { + + uvScaleMap = material.alphaMap; + + } else if ( material.emissiveMap ) { + + uvScaleMap = material.emissiveMap; + + } + + if ( uvScaleMap !== undefined ) { + + // backwards compatibility + if ( uvScaleMap.isWebGLRenderTarget ) { + + uvScaleMap = uvScaleMap.texture; + + } + + var offset = uvScaleMap.offset; + var repeat = uvScaleMap.repeat; + + uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); + + } + + uniforms.envMap.value = material.envMap; + + // don't flip CubeTexture envMaps, flip everything else: + // WebGLRenderTargetCube will be flipped for backwards compatibility + // WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture + // this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the future + uniforms.flipEnvMap.value = ( ! ( material.envMap && material.envMap.isCubeTexture ) ) ? 1 : - 1; + + uniforms.reflectivity.value = material.reflectivity; + uniforms.refractionRatio.value = material.refractionRatio; + + } + + function refreshUniformsLine( uniforms, material ) { + + uniforms.diffuse.value = material.color; + uniforms.opacity.value = material.opacity; + + } + + function refreshUniformsDash( uniforms, material ) { + + uniforms.dashSize.value = material.dashSize; + uniforms.totalSize.value = material.dashSize + material.gapSize; + uniforms.scale.value = material.scale; + + } + + function refreshUniformsPoints( uniforms, material ) { + + uniforms.diffuse.value = material.color; + uniforms.opacity.value = material.opacity; + uniforms.size.value = material.size * _pixelRatio; + uniforms.scale.value = _height * 0.5; + + uniforms.map.value = material.map; + + if ( material.map !== null ) { + + var offset = material.map.offset; + var repeat = material.map.repeat; + + uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); + + } + + } + + function refreshUniformsFog( uniforms, fog ) { + + uniforms.fogColor.value = fog.color; + + if ( fog.isFog ) { + + uniforms.fogNear.value = fog.near; + uniforms.fogFar.value = fog.far; + + } else if ( fog.isFogExp2 ) { + + uniforms.fogDensity.value = fog.density; + + } + + } + + function refreshUniformsLambert( uniforms, material ) { + + if ( material.emissiveMap ) { + + uniforms.emissiveMap.value = material.emissiveMap; + + } + + } + + function refreshUniformsPhong( uniforms, material ) { + + uniforms.specular.value = material.specular; + uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 ) + + if ( material.emissiveMap ) { + + uniforms.emissiveMap.value = material.emissiveMap; + + } + + if ( material.bumpMap ) { + + uniforms.bumpMap.value = material.bumpMap; + uniforms.bumpScale.value = material.bumpScale; + + } + + if ( material.normalMap ) { + + uniforms.normalMap.value = material.normalMap; + uniforms.normalScale.value.copy( material.normalScale ); + + } + + if ( material.displacementMap ) { + + uniforms.displacementMap.value = material.displacementMap; + uniforms.displacementScale.value = material.displacementScale; + uniforms.displacementBias.value = material.displacementBias; + + } + + } + + function refreshUniformsToon( uniforms, material ) { + + refreshUniformsPhong( uniforms, material ); + + if ( material.gradientMap ) { + + uniforms.gradientMap.value = material.gradientMap; + + } + + } + + function refreshUniformsStandard( uniforms, material ) { + + uniforms.roughness.value = material.roughness; + uniforms.metalness.value = material.metalness; + + if ( material.roughnessMap ) { + + uniforms.roughnessMap.value = material.roughnessMap; + + } + + if ( material.metalnessMap ) { + + uniforms.metalnessMap.value = material.metalnessMap; + + } + + if ( material.emissiveMap ) { + + uniforms.emissiveMap.value = material.emissiveMap; + + } + + if ( material.bumpMap ) { + + uniforms.bumpMap.value = material.bumpMap; + uniforms.bumpScale.value = material.bumpScale; + + } + + if ( material.normalMap ) { + + uniforms.normalMap.value = material.normalMap; + uniforms.normalScale.value.copy( material.normalScale ); + + } + + if ( material.displacementMap ) { + + uniforms.displacementMap.value = material.displacementMap; + uniforms.displacementScale.value = material.displacementScale; + uniforms.displacementBias.value = material.displacementBias; + + } + + if ( material.envMap ) { + + //uniforms.envMap.value = material.envMap; // part of uniforms common + uniforms.envMapIntensity.value = material.envMapIntensity; + + } + + } + + function refreshUniformsPhysical( uniforms, material ) { + + uniforms.clearCoat.value = material.clearCoat; + uniforms.clearCoatRoughness.value = material.clearCoatRoughness; + + refreshUniformsStandard( uniforms, material ); + + } + + function refreshUniformsNormal( uniforms, material ) { + + if ( material.bumpMap ) { + + uniforms.bumpMap.value = material.bumpMap; + uniforms.bumpScale.value = material.bumpScale; + + } + + if ( material.normalMap ) { + + uniforms.normalMap.value = material.normalMap; + uniforms.normalScale.value.copy( material.normalScale ); + + } + + if ( material.displacementMap ) { + + uniforms.displacementMap.value = material.displacementMap; + uniforms.displacementScale.value = material.displacementScale; + uniforms.displacementBias.value = material.displacementBias; + + } + + } + + // If uniforms are marked as clean, they don't need to be loaded to the GPU. + + function markUniformsLightsNeedsUpdate( uniforms, value ) { + + uniforms.ambientLightColor.needsUpdate = value; + + uniforms.directionalLights.needsUpdate = value; + uniforms.pointLights.needsUpdate = value; + uniforms.spotLights.needsUpdate = value; + uniforms.rectAreaLights.needsUpdate = value; + uniforms.hemisphereLights.needsUpdate = value; + + } + + // Lighting + + function setupShadows( lights ) { + + var lightShadowsLength = 0; + + for ( var i = 0, l = lights.length; i < l; i ++ ) { + + var light = lights[ i ]; + + if ( light.castShadow ) { + + _lights.shadows[ lightShadowsLength ++ ] = light; + + } + + } + + _lights.shadows.length = lightShadowsLength; + + } + + function setupLights( lights, camera ) { + + var l, ll, light, + r = 0, g = 0, b = 0, + color, + intensity, + distance, + shadowMap, + + viewMatrix = camera.matrixWorldInverse, + + directionalLength = 0, + pointLength = 0, + spotLength = 0, + rectAreaLength = 0, + hemiLength = 0; + + for ( l = 0, ll = lights.length; l < ll; l ++ ) { + + light = lights[ l ]; + + color = light.color; + intensity = light.intensity; + distance = light.distance; + + shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null; + + if ( light.isAmbientLight ) { + + r += color.r * intensity; + g += color.g * intensity; + b += color.b * intensity; + + } else if ( light.isDirectionalLight ) { + + var uniforms = lightCache.get( light ); + + uniforms.color.copy( light.color ).multiplyScalar( light.intensity ); + uniforms.direction.setFromMatrixPosition( light.matrixWorld ); + _vector3.setFromMatrixPosition( light.target.matrixWorld ); + uniforms.direction.sub( _vector3 ); + uniforms.direction.transformDirection( viewMatrix ); + + uniforms.shadow = light.castShadow; + + if ( light.castShadow ) { + + uniforms.shadowBias = light.shadow.bias; + uniforms.shadowRadius = light.shadow.radius; + uniforms.shadowMapSize = light.shadow.mapSize; + + } + + _lights.directionalShadowMap[ directionalLength ] = shadowMap; + _lights.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix; + _lights.directional[ directionalLength ++ ] = uniforms; + + } else if ( light.isSpotLight ) { + + var uniforms = lightCache.get( light ); + + uniforms.position.setFromMatrixPosition( light.matrixWorld ); + uniforms.position.applyMatrix4( viewMatrix ); + + uniforms.color.copy( color ).multiplyScalar( intensity ); + uniforms.distance = distance; + + uniforms.direction.setFromMatrixPosition( light.matrixWorld ); + _vector3.setFromMatrixPosition( light.target.matrixWorld ); + uniforms.direction.sub( _vector3 ); + uniforms.direction.transformDirection( viewMatrix ); + + uniforms.coneCos = Math.cos( light.angle ); + uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) ); + uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay; + + uniforms.shadow = light.castShadow; + + if ( light.castShadow ) { + + uniforms.shadowBias = light.shadow.bias; + uniforms.shadowRadius = light.shadow.radius; + uniforms.shadowMapSize = light.shadow.mapSize; + + } + + _lights.spotShadowMap[ spotLength ] = shadowMap; + _lights.spotShadowMatrix[ spotLength ] = light.shadow.matrix; + _lights.spot[ spotLength ++ ] = uniforms; + + } else if ( light.isRectAreaLight ) { + + var uniforms = lightCache.get( light ); + + // (a) intensity controls irradiance of entire light + uniforms.color + .copy( color ) + .multiplyScalar( intensity / ( light.width * light.height ) ); + + // (b) intensity controls the radiance per light area + // uniforms.color.copy( color ).multiplyScalar( intensity ); + + uniforms.position.setFromMatrixPosition( light.matrixWorld ); + uniforms.position.applyMatrix4( viewMatrix ); + + // extract local rotation of light to derive width/height half vectors + _matrix42.identity(); + _matrix4.copy( light.matrixWorld ); + _matrix4.premultiply( viewMatrix ); + _matrix42.extractRotation( _matrix4 ); + + uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); + uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); + + uniforms.halfWidth.applyMatrix4( _matrix42 ); + uniforms.halfHeight.applyMatrix4( _matrix42 ); + + // TODO (abelnation): RectAreaLight distance? + // uniforms.distance = distance; + + _lights.rectArea[ rectAreaLength ++ ] = uniforms; + + } else if ( light.isPointLight ) { + + var uniforms = lightCache.get( light ); + + uniforms.position.setFromMatrixPosition( light.matrixWorld ); + uniforms.position.applyMatrix4( viewMatrix ); + + uniforms.color.copy( light.color ).multiplyScalar( light.intensity ); + uniforms.distance = light.distance; + uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay; + + uniforms.shadow = light.castShadow; + + if ( light.castShadow ) { + + uniforms.shadowBias = light.shadow.bias; + uniforms.shadowRadius = light.shadow.radius; + uniforms.shadowMapSize = light.shadow.mapSize; + + } + + _lights.pointShadowMap[ pointLength ] = shadowMap; + + if ( _lights.pointShadowMatrix[ pointLength ] === undefined ) { + + _lights.pointShadowMatrix[ pointLength ] = new Matrix4(); + + } + + // for point lights we set the shadow matrix to be a translation-only matrix + // equal to inverse of the light's position + _vector3.setFromMatrixPosition( light.matrixWorld ).negate(); + _lights.pointShadowMatrix[ pointLength ].identity().setPosition( _vector3 ); + + _lights.point[ pointLength ++ ] = uniforms; + + } else if ( light.isHemisphereLight ) { + + var uniforms = lightCache.get( light ); + + uniforms.direction.setFromMatrixPosition( light.matrixWorld ); + uniforms.direction.transformDirection( viewMatrix ); + uniforms.direction.normalize(); + + uniforms.skyColor.copy( light.color ).multiplyScalar( intensity ); + uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity ); + + _lights.hemi[ hemiLength ++ ] = uniforms; + + } + + } + + _lights.ambient[ 0 ] = r; + _lights.ambient[ 1 ] = g; + _lights.ambient[ 2 ] = b; + + _lights.directional.length = directionalLength; + _lights.spot.length = spotLength; + _lights.rectArea.length = rectAreaLength; + _lights.point.length = pointLength; + _lights.hemi.length = hemiLength; + + // TODO (sam-g-steel) why aren't we using join + _lights.hash = directionalLength + ',' + pointLength + ',' + spotLength + ',' + rectAreaLength + ',' + hemiLength + ',' + _lights.shadows.length; + + } + + // GL state setting + + this.setFaceCulling = function ( cullFace, frontFaceDirection ) { + + state.setCullFace( cullFace ); + state.setFlipSided( frontFaceDirection === FrontFaceDirectionCW ); + + }; + + // Textures + + function allocTextureUnit() { + + var textureUnit = _usedTextureUnits; + + if ( textureUnit >= capabilities.maxTextures ) { + + console.warn( 'WebGLRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures ); + + } + + _usedTextureUnits += 1; + + return textureUnit; + + } + + this.allocTextureUnit = allocTextureUnit; + + // this.setTexture2D = setTexture2D; + this.setTexture2D = ( function() { + + var warned = false; + + // backwards compatibility: peel texture.texture + return function setTexture2D( texture, slot ) { + + if ( texture && texture.isWebGLRenderTarget ) { + + if ( ! warned ) { + + console.warn( "THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead." ); + warned = true; + + } + + texture = texture.texture; + + } + + textures.setTexture2D( texture, slot ); + + }; + + }() ); + + this.setTexture = ( function() { + + var warned = false; + + return function setTexture( texture, slot ) { + + if ( ! warned ) { + + console.warn( "THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead." ); + warned = true; + + } + + textures.setTexture2D( texture, slot ); + + }; + + }() ); + + this.setTextureCube = ( function() { + + var warned = false; + + return function setTextureCube( texture, slot ) { + + // backwards compatibility: peel texture.texture + if ( texture && texture.isWebGLRenderTargetCube ) { + + if ( ! warned ) { + + console.warn( "THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead." ); + warned = true; + + } + + texture = texture.texture; + + } + + // currently relying on the fact that WebGLRenderTargetCube.texture is a Texture and NOT a CubeTexture + // TODO: unify these code paths + if ( ( texture && texture.isCubeTexture ) || + ( Array.isArray( texture.image ) && texture.image.length === 6 ) ) { + + // CompressedTexture can have Array in image :/ + + // this function alone should take care of cube textures + textures.setTextureCube( texture, slot ); + + } else { + + // assumed: texture property of THREE.WebGLRenderTargetCube + + textures.setTextureCubeDynamic( texture, slot ); + + } + + }; + + }() ); + + this.getCurrentRenderTarget = function() { + + return _currentRenderTarget; + + }; + + this.setRenderTarget = function ( renderTarget ) { + + _currentRenderTarget = renderTarget; + + if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) { + + textures.setupRenderTarget( renderTarget ); + + } + + var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube ); + var framebuffer; + + if ( renderTarget ) { + + var renderTargetProperties = properties.get( renderTarget ); + + if ( isCube ) { + + framebuffer = renderTargetProperties.__webglFramebuffer[ renderTarget.activeCubeFace ]; + + } else { + + framebuffer = renderTargetProperties.__webglFramebuffer; + + } + + _currentScissor.copy( renderTarget.scissor ); + _currentScissorTest = renderTarget.scissorTest; + + _currentViewport.copy( renderTarget.viewport ); + + } else { + + framebuffer = null; + + _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ); + _currentScissorTest = _scissorTest; + + _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ); + + } + + if ( _currentFramebuffer !== framebuffer ) { + + _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + _currentFramebuffer = framebuffer; + + } + + state.scissor( _currentScissor ); + state.setScissorTest( _currentScissorTest ); + + state.viewport( _currentViewport ); + + if ( isCube ) { + + var textureProperties = properties.get( renderTarget.texture ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, textureProperties.__webglTexture, renderTarget.activeMipMapLevel ); + + } + + }; + + this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer ) { + + if ( ( renderTarget && renderTarget.isWebGLRenderTarget ) === false ) { + + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); + return; + + } + + var framebuffer = properties.get( renderTarget ).__webglFramebuffer; + + if ( framebuffer ) { + + var restore = false; + + if ( framebuffer !== _currentFramebuffer ) { + + _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + + restore = true; + + } + + try { + + var texture = renderTarget.texture; + var textureFormat = texture.format; + var textureType = texture.type; + + if ( textureFormat !== RGBAFormat && paramThreeToGL( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) { + + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); + return; + + } + + if ( textureType !== UnsignedByteType && paramThreeToGL( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // IE11, Edge and Chrome Mac < 52 (#9513) + ! ( textureType === FloatType && ( extensions.get( 'OES_texture_float' ) || extensions.get( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox + ! ( textureType === HalfFloatType && extensions.get( 'EXT_color_buffer_half_float' ) ) ) { + + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); + return; + + } + + if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) { + + // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) + + if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { + + _gl.readPixels( x, y, width, height, paramThreeToGL( textureFormat ), paramThreeToGL( textureType ), buffer ); + + } + + } else { + + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); + + } + + } finally { + + if ( restore ) { + + _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer ); + + } + + } + + } + + }; + + // Map three.js constants to WebGL constants + + function paramThreeToGL( p ) { + + var extension; + + if ( p === RepeatWrapping ) return _gl.REPEAT; + if ( p === ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE; + if ( p === MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT; + + if ( p === NearestFilter ) return _gl.NEAREST; + if ( p === NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST; + if ( p === NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR; + + if ( p === LinearFilter ) return _gl.LINEAR; + if ( p === LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST; + if ( p === LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR; + + if ( p === UnsignedByteType ) return _gl.UNSIGNED_BYTE; + if ( p === UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4; + if ( p === UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1; + if ( p === UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5; + + if ( p === ByteType ) return _gl.BYTE; + if ( p === ShortType ) return _gl.SHORT; + if ( p === UnsignedShortType ) return _gl.UNSIGNED_SHORT; + if ( p === IntType ) return _gl.INT; + if ( p === UnsignedIntType ) return _gl.UNSIGNED_INT; + if ( p === FloatType ) return _gl.FLOAT; + + if ( p === HalfFloatType ) { + + extension = extensions.get( 'OES_texture_half_float' ); + + if ( extension !== null ) return extension.HALF_FLOAT_OES; + + } + + if ( p === AlphaFormat ) return _gl.ALPHA; + if ( p === RGBFormat ) return _gl.RGB; + if ( p === RGBAFormat ) return _gl.RGBA; + if ( p === LuminanceFormat ) return _gl.LUMINANCE; + if ( p === LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA; + if ( p === DepthFormat ) return _gl.DEPTH_COMPONENT; + if ( p === DepthStencilFormat ) return _gl.DEPTH_STENCIL; + + if ( p === AddEquation ) return _gl.FUNC_ADD; + if ( p === SubtractEquation ) return _gl.FUNC_SUBTRACT; + if ( p === ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT; + + if ( p === ZeroFactor ) return _gl.ZERO; + if ( p === OneFactor ) return _gl.ONE; + if ( p === SrcColorFactor ) return _gl.SRC_COLOR; + if ( p === OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR; + if ( p === SrcAlphaFactor ) return _gl.SRC_ALPHA; + if ( p === OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA; + if ( p === DstAlphaFactor ) return _gl.DST_ALPHA; + if ( p === OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA; + + if ( p === DstColorFactor ) return _gl.DST_COLOR; + if ( p === OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR; + if ( p === SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE; + + if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || + p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) { + + extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); + + if ( extension !== null ) { + + if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; + if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; + if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; + if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; + + } + + } + + if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || + p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) { + + extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); + + if ( extension !== null ) { + + if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + + } + + } + + if ( p === RGB_ETC1_Format ) { + + extension = extensions.get( 'WEBGL_compressed_texture_etc1' ); + + if ( extension !== null ) return extension.COMPRESSED_RGB_ETC1_WEBGL; + + } + + if ( p === MinEquation || p === MaxEquation ) { + + extension = extensions.get( 'EXT_blend_minmax' ); + + if ( extension !== null ) { + + if ( p === MinEquation ) return extension.MIN_EXT; + if ( p === MaxEquation ) return extension.MAX_EXT; + + } + + } + + if ( p === UnsignedInt248Type ) { + + extension = extensions.get( 'WEBGL_depth_texture' ); + + if ( extension !== null ) return extension.UNSIGNED_INT_24_8_WEBGL; + + } + + return 0; + + } + +} + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +function FogExp2 ( color, density ) { + + this.name = ''; + + this.color = new Color( color ); + this.density = ( density !== undefined ) ? density : 0.00025; + +} + +FogExp2.prototype.isFogExp2 = true; + +FogExp2.prototype.clone = function () { + + return new FogExp2( this.color.getHex(), this.density ); + +}; + +FogExp2.prototype.toJSON = function ( meta ) { + + return { + type: 'FogExp2', + color: this.color.getHex(), + density: this.density + }; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +function Fog ( color, near, far ) { + + this.name = ''; + + this.color = new Color( color ); + + this.near = ( near !== undefined ) ? near : 1; + this.far = ( far !== undefined ) ? far : 1000; + +} + +Fog.prototype.isFog = true; + +Fog.prototype.clone = function () { + + return new Fog( this.color.getHex(), this.near, this.far ); + +}; + +Fog.prototype.toJSON = function ( meta ) { + + return { + type: 'Fog', + color: this.color.getHex(), + near: this.near, + far: this.far + }; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function Scene () { + + Object3D.call( this ); + + this.type = 'Scene'; + + this.background = null; + this.fog = null; + this.overrideMaterial = null; + + this.autoUpdate = true; // checked by the renderer + +} + +Scene.prototype = Object.create( Object3D.prototype ); + +Scene.prototype.constructor = Scene; + +Scene.prototype.copy = function ( source, recursive ) { + + Object3D.prototype.copy.call( this, source, recursive ); + + if ( source.background !== null ) this.background = source.background.clone(); + if ( source.fog !== null ) this.fog = source.fog.clone(); + if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone(); + + this.autoUpdate = source.autoUpdate; + this.matrixAutoUpdate = source.matrixAutoUpdate; + + return this; + +}; + +Scene.prototype.toJSON = function ( meta ) { + + var data = Object3D.prototype.toJSON.call( this, meta ); + + if ( this.background !== null ) data.object.background = this.background.toJSON( meta ); + if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); + + return data; + +}; + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +function LensFlare( texture, size, distance, blending, color ) { + + Object3D.call( this ); + + this.lensFlares = []; + + this.positionScreen = new Vector3(); + this.customUpdateCallback = undefined; + + if ( texture !== undefined ) { + + this.add( texture, size, distance, blending, color ); + + } + +} + +LensFlare.prototype = Object.assign( Object.create( Object3D.prototype ), { + + constructor: LensFlare, + + isLensFlare: true, + + copy: function ( source ) { + + Object3D.prototype.copy.call( this, source ); + + this.positionScreen.copy( source.positionScreen ); + this.customUpdateCallback = source.customUpdateCallback; + + for ( var i = 0, l = source.lensFlares.length; i < l; i ++ ) { + + this.lensFlares.push( source.lensFlares[ i ] ); + + } + + return this; + + }, + + add: function ( texture, size, distance, blending, color, opacity ) { + + if ( size === undefined ) size = - 1; + if ( distance === undefined ) distance = 0; + if ( opacity === undefined ) opacity = 1; + if ( color === undefined ) color = new Color( 0xffffff ); + if ( blending === undefined ) blending = NormalBlending; + + distance = Math.min( distance, Math.max( 0, distance ) ); + + this.lensFlares.push( { + texture: texture, // THREE.Texture + size: size, // size in pixels (-1 = use texture.width) + distance: distance, // distance (0-1) from light source (0=at light source) + x: 0, y: 0, z: 0, // screen position (-1 => 1) z = 0 is in front z = 1 is back + scale: 1, // scale + rotation: 0, // rotation + opacity: opacity, // opacity + color: color, // color + blending: blending // blending + } ); + + }, + + /* + * Update lens flares update positions on all flares based on the screen position + * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way. + */ + + updateLensFlares: function () { + + var f, fl = this.lensFlares.length; + var flare; + var vecX = - this.positionScreen.x * 2; + var vecY = - this.positionScreen.y * 2; + + for ( f = 0; f < fl; f ++ ) { + + flare = this.lensFlares[ f ]; + + flare.x = this.positionScreen.x + vecX * flare.distance; + flare.y = this.positionScreen.y + vecY * flare.distance; + + flare.wantedRotation = flare.x * Math.PI * 0.25; + flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25; + + } + + } + +} ); + +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * map: new THREE.Texture( ), + * + * uvOffset: new THREE.Vector2(), + * uvScale: new THREE.Vector2() + * } + */ + +function SpriteMaterial( parameters ) { + + Material.call( this ); + + this.type = 'SpriteMaterial'; + + this.color = new Color( 0xffffff ); + this.map = null; + + this.rotation = 0; + + this.fog = false; + this.lights = false; + + this.setValues( parameters ); + +} + +SpriteMaterial.prototype = Object.create( Material.prototype ); +SpriteMaterial.prototype.constructor = SpriteMaterial; + +SpriteMaterial.prototype.copy = function ( source ) { + + Material.prototype.copy.call( this, source ); + + this.color.copy( source.color ); + this.map = source.map; + + this.rotation = source.rotation; + + return this; + +}; + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +function Sprite( material ) { + + Object3D.call( this ); + + this.type = 'Sprite'; + + this.material = ( material !== undefined ) ? material : new SpriteMaterial(); + +} + +Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), { + + constructor: Sprite, + + isSprite: true, + + raycast: ( function () { + + var matrixPosition = new Vector3(); + + return function raycast( raycaster, intersects ) { + + matrixPosition.setFromMatrixPosition( this.matrixWorld ); + + var distanceSq = raycaster.ray.distanceSqToPoint( matrixPosition ); + var guessSizeSq = this.scale.x * this.scale.y / 4; + + if ( distanceSq > guessSizeSq ) { + + return; + + } + + intersects.push( { + + distance: Math.sqrt( distanceSq ), + point: this.position, + face: null, + object: this + + } ); + + }; + + }() ), + + clone: function () { + + return new this.constructor( this.material ).copy( this ); + + } + +} ); + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ + +function LOD() { + + Object3D.call( this ); + + this.type = 'LOD'; + + Object.defineProperties( this, { + levels: { + enumerable: true, + value: [] + } + } ); + +} + + +LOD.prototype = Object.assign( Object.create( Object3D.prototype ), { + + constructor: LOD, + + copy: function ( source ) { + + Object3D.prototype.copy.call( this, source, false ); + + var levels = source.levels; + + for ( var i = 0, l = levels.length; i < l; i ++ ) { + + var level = levels[ i ]; + + this.addLevel( level.object.clone(), level.distance ); + + } + + return this; + + }, + + addLevel: function ( object, distance ) { + + if ( distance === undefined ) distance = 0; + + distance = Math.abs( distance ); + + var levels = this.levels; + + for ( var l = 0; l < levels.length; l ++ ) { + + if ( distance < levels[ l ].distance ) { + + break; + + } + + } + + levels.splice( l, 0, { distance: distance, object: object } ); + + this.add( object ); + + }, + + getObjectForDistance: function ( distance ) { + + var levels = this.levels; + + for ( var i = 1, l = levels.length; i < l; i ++ ) { + + if ( distance < levels[ i ].distance ) { + + break; + + } + + } + + return levels[ i - 1 ].object; + + }, + + raycast: ( function () { + + var matrixPosition = new Vector3(); + + return function raycast( raycaster, intersects ) { + + matrixPosition.setFromMatrixPosition( this.matrixWorld ); + + var distance = raycaster.ray.origin.distanceTo( matrixPosition ); + + this.getObjectForDistance( distance ).raycast( raycaster, intersects ); + + }; + + }() ), + + update: function () { + + var v1 = new Vector3(); + var v2 = new Vector3(); + + return function update( camera ) { + + var levels = this.levels; + + if ( levels.length > 1 ) { + + v1.setFromMatrixPosition( camera.matrixWorld ); + v2.setFromMatrixPosition( this.matrixWorld ); + + var distance = v1.distanceTo( v2 ); + + levels[ 0 ].object.visible = true; + + for ( var i = 1, l = levels.length; i < l; i ++ ) { + + if ( distance >= levels[ i ].distance ) { + + levels[ i - 1 ].object.visible = false; + levels[ i ].object.visible = true; + + } else { + + break; + + } + + } + + for ( ; i < l; i ++ ) { + + levels[ i ].object.visible = false; + + } + + } + + }; + + }(), + + toJSON: function ( meta ) { + + var data = Object3D.prototype.toJSON.call( this, meta ); + + data.object.levels = []; + + var levels = this.levels; + + for ( var i = 0, l = levels.length; i < l; i ++ ) { + + var level = levels[ i ]; + + data.object.levels.push( { + object: level.object.uuid, + distance: level.distance + } ); + + } + + return data; + + } + +} ); + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author michael guerrero / http://realitymeltdown.com + * @author ikerr / http://verold.com + */ + +function Skeleton( bones, boneInverses, useVertexTexture ) { + + this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true; + + this.identityMatrix = new Matrix4(); + + // copy the bone array + + bones = bones || []; + + this.bones = bones.slice( 0 ); + + // create a bone texture or an array of floats + + if ( this.useVertexTexture ) { + + // layout (1 matrix = 4 pixels) + // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) + // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8) + // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16) + // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32) + // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64) + + + var size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix + size = _Math.nextPowerOfTwo( Math.ceil( size ) ); + size = Math.max( size, 4 ); + + this.boneTextureWidth = size; + this.boneTextureHeight = size; + + this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel + this.boneTexture = new DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, RGBAFormat, FloatType ); + + } else { + + this.boneMatrices = new Float32Array( 16 * this.bones.length ); + + } + + // use the supplied bone inverses or calculate the inverses + + if ( boneInverses === undefined ) { + + this.calculateInverses(); + + } else { + + if ( this.bones.length === boneInverses.length ) { + + this.boneInverses = boneInverses.slice( 0 ); + + } else { + + console.warn( 'THREE.Skeleton bonInverses is the wrong length.' ); + + this.boneInverses = []; + + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { + + this.boneInverses.push( new Matrix4() ); + + } + + } + + } + +} + +Object.assign( Skeleton.prototype, { + + calculateInverses: function () { + + this.boneInverses = []; + + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { + + var inverse = new Matrix4(); + + if ( this.bones[ b ] ) { + + inverse.getInverse( this.bones[ b ].matrixWorld ); + + } + + this.boneInverses.push( inverse ); + + } + + }, + + pose: function () { + + var bone; + + // recover the bind-time world matrices + + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { + + bone = this.bones[ b ]; + + if ( bone ) { + + bone.matrixWorld.getInverse( this.boneInverses[ b ] ); + + } + + } + + // compute the local matrices, positions, rotations and scales + + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { + + bone = this.bones[ b ]; + + if ( bone ) { + + if ( bone.parent && bone.parent.isBone ) { + + bone.matrix.getInverse( bone.parent.matrixWorld ); + bone.matrix.multiply( bone.matrixWorld ); + + } else { + + bone.matrix.copy( bone.matrixWorld ); + + } + + bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); + + } + + } + + }, + + update: ( function () { + + var offsetMatrix = new Matrix4(); + + return function update() { + + // flatten bone matrices to array + + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { + + // compute the offset between the current and the original transform + + var matrix = this.bones[ b ] ? this.bones[ b ].matrixWorld : this.identityMatrix; + + offsetMatrix.multiplyMatrices( matrix, this.boneInverses[ b ] ); + offsetMatrix.toArray( this.boneMatrices, b * 16 ); + + } + + if ( this.useVertexTexture ) { + + this.boneTexture.needsUpdate = true; + + } + + }; + + } )(), + + clone: function () { + + return new Skeleton( this.bones, this.boneInverses, this.useVertexTexture ); + + } + +} ); + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author ikerr / http://verold.com + */ + +function Bone() { + + Object3D.call( this ); + + this.type = 'Bone'; + +} + +Bone.prototype = Object.assign( Object.create( Object3D.prototype ), { + + constructor: Bone, + + isBone: true + +} ); + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author ikerr / http://verold.com + */ + +function SkinnedMesh( geometry, material, useVertexTexture ) { + + Mesh.call( this, geometry, material ); + + this.type = 'SkinnedMesh'; + + this.bindMode = "attached"; + this.bindMatrix = new Matrix4(); + this.bindMatrixInverse = new Matrix4(); + + // init bones + + // TODO: remove bone creation as there is no reason (other than + // convenience) for THREE.SkinnedMesh to do this. + + var bones = []; + + if ( this.geometry && this.geometry.bones !== undefined ) { + + var bone, gbone; + + for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { + + gbone = this.geometry.bones[ b ]; + + bone = new Bone(); + bones.push( bone ); + + bone.name = gbone.name; + bone.position.fromArray( gbone.pos ); + bone.quaternion.fromArray( gbone.rotq ); + if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl ); + + } + + for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { + + gbone = this.geometry.bones[ b ]; + + if ( gbone.parent !== - 1 && gbone.parent !== null && + bones[ gbone.parent ] !== undefined ) { + + bones[ gbone.parent ].add( bones[ b ] ); + + } else { + + this.add( bones[ b ] ); + + } + + } + + } + + this.normalizeSkinWeights(); + + this.updateMatrixWorld( true ); + this.bind( new Skeleton( bones, undefined, useVertexTexture ), this.matrixWorld ); + +} + + +SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), { + + constructor: SkinnedMesh, + + isSkinnedMesh: true, + + bind: function( skeleton, bindMatrix ) { + + this.skeleton = skeleton; + + if ( bindMatrix === undefined ) { + + this.updateMatrixWorld( true ); + + this.skeleton.calculateInverses(); + + bindMatrix = this.matrixWorld; + + } + + this.bindMatrix.copy( bindMatrix ); + this.bindMatrixInverse.getInverse( bindMatrix ); + + }, + + pose: function () { + + this.skeleton.pose(); + + }, + + normalizeSkinWeights: function () { + + if ( this.geometry && this.geometry.isGeometry ) { + + for ( var i = 0; i < this.geometry.skinWeights.length; i ++ ) { + + var sw = this.geometry.skinWeights[ i ]; + + var scale = 1.0 / sw.lengthManhattan(); + + if ( scale !== Infinity ) { + + sw.multiplyScalar( scale ); + + } else { + + sw.set( 1, 0, 0, 0 ); // do something reasonable + + } + + } + + } else if ( this.geometry && this.geometry.isBufferGeometry ) { + + var vec = new Vector4(); + + var skinWeight = this.geometry.attributes.skinWeight; + + for ( var i = 0; i < skinWeight.count; i ++ ) { + + vec.x = skinWeight.getX( i ); + vec.y = skinWeight.getY( i ); + vec.z = skinWeight.getZ( i ); + vec.w = skinWeight.getW( i ); + + var scale = 1.0 / vec.lengthManhattan(); + + if ( scale !== Infinity ) { + + vec.multiplyScalar( scale ); + + } else { + + vec.set( 1, 0, 0, 0 ); // do something reasonable + + } + + skinWeight.setXYZW( i, vec.x, vec.y, vec.z, vec.w ); + + } + + } + + }, + + updateMatrixWorld: function( force ) { + + Mesh.prototype.updateMatrixWorld.call( this, true ); + + if ( this.bindMode === "attached" ) { + + this.bindMatrixInverse.getInverse( this.matrixWorld ); + + } else if ( this.bindMode === "detached" ) { + + this.bindMatrixInverse.getInverse( this.bindMatrix ); + + } else { + + console.warn( 'THREE.SkinnedMesh unrecognized bindMode: ' + this.bindMode ); + + } + + }, + + clone: function() { + + return new this.constructor( this.geometry, this.material, this.skeleton.useVertexTexture ).copy( this ); + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * + * linewidth: , + * linecap: "round", + * linejoin: "round" + * } + */ + +function LineBasicMaterial( parameters ) { + + Material.call( this ); + + this.type = 'LineBasicMaterial'; + + this.color = new Color( 0xffffff ); + + this.linewidth = 1; + this.linecap = 'round'; + this.linejoin = 'round'; + + this.lights = false; + + this.setValues( parameters ); + +} + +LineBasicMaterial.prototype = Object.create( Material.prototype ); +LineBasicMaterial.prototype.constructor = LineBasicMaterial; + +LineBasicMaterial.prototype.isLineBasicMaterial = true; + +LineBasicMaterial.prototype.copy = function ( source ) { + + Material.prototype.copy.call( this, source ); + + this.color.copy( source.color ); + + this.linewidth = source.linewidth; + this.linecap = source.linecap; + this.linejoin = source.linejoin; + + return this; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function Line( geometry, material, mode ) { + + if ( mode === 1 ) { + + console.warn( 'THREE.Line: parameter THREE.LinePieces no longer supported. Created THREE.LineSegments instead.' ); + return new LineSegments( geometry, material ); + + } + + Object3D.call( this ); + + this.type = 'Line'; + + this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); + this.material = material !== undefined ? material : new LineBasicMaterial( { color: Math.random() * 0xffffff } ); + +} + +Line.prototype = Object.assign( Object.create( Object3D.prototype ), { + + constructor: Line, + + isLine: true, + + raycast: ( function () { + + var inverseMatrix = new Matrix4(); + var ray = new Ray(); + var sphere = new Sphere(); + + return function raycast( raycaster, intersects ) { + + var precision = raycaster.linePrecision; + var precisionSq = precision * precision; + + var geometry = this.geometry; + var matrixWorld = this.matrixWorld; + + // Checking boundingSphere distance to ray + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( matrixWorld ); + + if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; + + // + + inverseMatrix.getInverse( matrixWorld ); + ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); + + var vStart = new Vector3(); + var vEnd = new Vector3(); + var interSegment = new Vector3(); + var interRay = new Vector3(); + var step = (this && this.isLineSegments) ? 2 : 1; + + if ( geometry.isBufferGeometry ) { + + var index = geometry.index; + var attributes = geometry.attributes; + var positions = attributes.position.array; + + if ( index !== null ) { + + var indices = index.array; + + for ( var i = 0, l = indices.length - 1; i < l; i += step ) { + + var a = indices[ i ]; + var b = indices[ i + 1 ]; + + vStart.fromArray( positions, a * 3 ); + vEnd.fromArray( positions, b * 3 ); + + var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); + + if ( distSq > precisionSq ) continue; + + interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation + + var distance = raycaster.ray.origin.distanceTo( interRay ); + + if ( distance < raycaster.near || distance > raycaster.far ) continue; + + intersects.push( { + + distance: distance, + // What do we want? intersection point on the ray or on the segment?? + // point: raycaster.ray.at( distance ), + point: interSegment.clone().applyMatrix4( this.matrixWorld ), + index: i, + face: null, + faceIndex: null, + object: this + + } ); + + } + + } else { + + for ( var i = 0, l = positions.length / 3 - 1; i < l; i += step ) { + + vStart.fromArray( positions, 3 * i ); + vEnd.fromArray( positions, 3 * i + 3 ); + + var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); + + if ( distSq > precisionSq ) continue; + + interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation + + var distance = raycaster.ray.origin.distanceTo( interRay ); + + if ( distance < raycaster.near || distance > raycaster.far ) continue; + + intersects.push( { + + distance: distance, + // What do we want? intersection point on the ray or on the segment?? + // point: raycaster.ray.at( distance ), + point: interSegment.clone().applyMatrix4( this.matrixWorld ), + index: i, + face: null, + faceIndex: null, + object: this + + } ); + + } + + } + + } else if ( geometry.isGeometry ) { + + var vertices = geometry.vertices; + var nbVertices = vertices.length; + + for ( var i = 0; i < nbVertices - 1; i += step ) { + + var distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment ); + + if ( distSq > precisionSq ) continue; + + interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation + + var distance = raycaster.ray.origin.distanceTo( interRay ); + + if ( distance < raycaster.near || distance > raycaster.far ) continue; + + intersects.push( { + + distance: distance, + // What do we want? intersection point on the ray or on the segment?? + // point: raycaster.ray.at( distance ), + point: interSegment.clone().applyMatrix4( this.matrixWorld ), + index: i, + face: null, + faceIndex: null, + object: this + + } ); + + } + + } + + }; + + }() ), + + clone: function () { + + return new this.constructor( this.geometry, this.material ).copy( this ); + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function LineSegments( geometry, material ) { + + Line.call( this, geometry, material ); + + this.type = 'LineSegments'; + +} + +LineSegments.prototype = Object.assign( Object.create( Line.prototype ), { + + constructor: LineSegments, + + isLineSegments: true + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * map: new THREE.Texture( ), + * + * size: , + * sizeAttenuation: + * } + */ + +function PointsMaterial( parameters ) { + + Material.call( this ); + + this.type = 'PointsMaterial'; + + this.color = new Color( 0xffffff ); + + this.map = null; + + this.size = 1; + this.sizeAttenuation = true; + + this.lights = false; + + this.setValues( parameters ); + +} + +PointsMaterial.prototype = Object.create( Material.prototype ); +PointsMaterial.prototype.constructor = PointsMaterial; + +PointsMaterial.prototype.isPointsMaterial = true; + +PointsMaterial.prototype.copy = function ( source ) { + + Material.prototype.copy.call( this, source ); + + this.color.copy( source.color ); + + this.map = source.map; + + this.size = source.size; + this.sizeAttenuation = source.sizeAttenuation; + + return this; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +function Points( geometry, material ) { + + Object3D.call( this ); + + this.type = 'Points'; + + this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); + this.material = material !== undefined ? material : new PointsMaterial( { color: Math.random() * 0xffffff } ); + +} + +Points.prototype = Object.assign( Object.create( Object3D.prototype ), { + + constructor: Points, + + isPoints: true, + + raycast: ( function () { + + var inverseMatrix = new Matrix4(); + var ray = new Ray(); + var sphere = new Sphere(); + + return function raycast( raycaster, intersects ) { + + var object = this; + var geometry = this.geometry; + var matrixWorld = this.matrixWorld; + var threshold = raycaster.params.Points.threshold; + + // Checking boundingSphere distance to ray + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( matrixWorld ); + + if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; + + // + + inverseMatrix.getInverse( matrixWorld ); + ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); + + var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); + var localThresholdSq = localThreshold * localThreshold; + var position = new Vector3(); + + function testPoint( point, index ) { + + var rayPointDistanceSq = ray.distanceSqToPoint( point ); + + if ( rayPointDistanceSq < localThresholdSq ) { + + var intersectPoint = ray.closestPointToPoint( point ); + intersectPoint.applyMatrix4( matrixWorld ); + + var distance = raycaster.ray.origin.distanceTo( intersectPoint ); + + if ( distance < raycaster.near || distance > raycaster.far ) return; + + intersects.push( { + + distance: distance, + distanceToRay: Math.sqrt( rayPointDistanceSq ), + point: intersectPoint.clone(), + index: index, + face: null, + object: object + + } ); + + } + + } + + if ( geometry.isBufferGeometry ) { + + var index = geometry.index; + var attributes = geometry.attributes; + var positions = attributes.position.array; + + if ( index !== null ) { + + var indices = index.array; + + for ( var i = 0, il = indices.length; i < il; i ++ ) { + + var a = indices[ i ]; + + position.fromArray( positions, a * 3 ); + + testPoint( position, a ); + + } + + } else { + + for ( var i = 0, l = positions.length / 3; i < l; i ++ ) { + + position.fromArray( positions, i * 3 ); + + testPoint( position, i ); + + } + + } + + } else { + + var vertices = geometry.vertices; + + for ( var i = 0, l = vertices.length; i < l; i ++ ) { + + testPoint( vertices[ i ], i ); + + } + + } + + }; + + }() ), + + clone: function () { + + return new this.constructor( this.geometry, this.material ).copy( this ); + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function Group() { + + Object3D.call( this ); + + this.type = 'Group'; + +} + +Group.prototype = Object.assign( Object.create( Object3D.prototype ), { + + constructor: Group + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function VideoTexture( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { + + Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + this.generateMipmaps = false; + + var scope = this; + + function update() { + + requestAnimationFrame( update ); + + if ( video.readyState >= video.HAVE_CURRENT_DATA ) { + + scope.needsUpdate = true; + + } + + } + + update(); + +} + +VideoTexture.prototype = Object.create( Texture.prototype ); +VideoTexture.prototype.constructor = VideoTexture; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +function CompressedTexture( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) { + + Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); + + this.image = { width: width, height: height }; + this.mipmaps = mipmaps; + + // no flipping for cube textures + // (also flipping doesn't work for compressed textures ) + + this.flipY = false; + + // can't generate mipmaps for compressed textures + // mips must be embedded in DDS files + + this.generateMipmaps = false; + +} + +CompressedTexture.prototype = Object.create( Texture.prototype ); +CompressedTexture.prototype.constructor = CompressedTexture; + +CompressedTexture.prototype.isCompressedTexture = true; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { + + Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + this.needsUpdate = true; + +} + +CanvasTexture.prototype = Object.create( Texture.prototype ); +CanvasTexture.prototype.constructor = CanvasTexture; + +/** + * @author Matt DesLauriers / @mattdesl + * @author atix / arthursilber.de + */ + +function DepthTexture( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { + + format = format !== undefined ? format : DepthFormat; + + if ( format !== DepthFormat && format !== DepthStencilFormat ) { + + throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ) + + } + + if ( type === undefined && format === DepthFormat ) type = UnsignedShortType; + if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; + + Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + this.image = { width: width, height: height }; + + this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; + this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; + + this.flipY = false; + this.generateMipmaps = false; + +} + +DepthTexture.prototype = Object.create( Texture.prototype ); +DepthTexture.prototype.constructor = DepthTexture; +DepthTexture.prototype.isDepthTexture = true; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author Mugen87 / https://github.com/Mugen87 + */ + +function WireframeGeometry( geometry ) { + + BufferGeometry.call( this ); + + this.type = 'WireframeGeometry'; + + // buffer + + var vertices = []; + + // helper variables + + var i, j, l, o, ol; + var edge = [ 0, 0 ], edges = {}, e; + var key, keys = [ 'a', 'b', 'c' ]; + var vertex; + + // different logic for Geometry and BufferGeometry + + if ( geometry && geometry.isGeometry ) { + + // create a data structure that contains all edges without duplicates + + var faces = geometry.faces; + + for ( i = 0, l = faces.length; i < l; i ++ ) { + + var face = faces[ i ]; + + for ( j = 0; j < 3; j ++ ) { + + edge[ 0 ] = face[ keys[ j ] ]; + edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; + edge.sort( sortFunction ); // sorting prevents duplicates + + key = edge.toString(); + + if ( edges[ key ] === undefined ) { + + edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] }; + + } + + } + + } + + // generate vertices + + for ( key in edges ) { + + e = edges[ key ]; + + vertex = geometry.vertices[ e.index1 ]; + vertices.push( vertex.x, vertex.y, vertex.z ); + + vertex = geometry.vertices[ e.index2 ]; + vertices.push( vertex.x, vertex.y, vertex.z ); + + } + + } else if ( geometry && geometry.isBufferGeometry ) { + + var position, indices, groups; + var group, start, count; + var index1, index2; + + vertex = new Vector3(); + + if ( geometry.index !== null ) { + + // indexed BufferGeometry + + position = geometry.attributes.position; + indices = geometry.index; + groups = geometry.groups; + + if ( groups.length === 0 ) { + + geometry.addGroup( 0, indices.count ); + + } + + // create a data structure that contains all eges without duplicates + + for ( o = 0, ol = groups.length; o < ol; ++ o ) { + + group = groups[ o ]; + + start = group.start; + count = group.count; + + for ( i = start, l = ( start + count ); i < l; i += 3 ) { + + for ( j = 0; j < 3; j ++ ) { + + edge[ 0 ] = indices.getX( i + j ); + edge[ 1 ] = indices.getX( i + ( j + 1 ) % 3 ); + edge.sort( sortFunction ); // sorting prevents duplicates + + key = edge.toString(); + + if ( edges[ key ] === undefined ) { + + edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] }; + + } + + } + + } + + } + + // generate vertices + + for ( key in edges ) { + + e = edges[ key ]; + + vertex.fromBufferAttribute( position, e.index1 ); + vertices.push( vertex.x, vertex.y, vertex.z ); + + vertex.fromBufferAttribute( position, e.index2 ); + vertices.push( vertex.x, vertex.y, vertex.z ); + + } + + } else { + + // non-indexed BufferGeometry + + position = geometry.attributes.position; + + for ( i = 0, l = ( position.count / 3 ); i < l; i ++ ) { + + for ( j = 0; j < 3; j ++ ) { + + // three edges per triangle, an edge is represented as (index1, index2) + // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0) + + index1 = 3 * i + j; + vertex.fromBufferAttribute( position, index1 ); + vertices.push( vertex.x, vertex.y, vertex.z ); + + index2 = 3 * i + ( ( j + 1 ) % 3 ); + vertex.fromBufferAttribute( position, index2 ); + vertices.push( vertex.x, vertex.y, vertex.z ); + + } + + } + + } + + } + + // build geometry + + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + + // custom array sort function + + function sortFunction( a, b ) { + + return a - b; + + } + +} + +WireframeGeometry.prototype = Object.create( BufferGeometry.prototype ); +WireframeGeometry.prototype.constructor = WireframeGeometry; + +/** + * @author zz85 / https://github.com/zz85 + * + * Parametric Surfaces Geometry + * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 + */ + +function ParametricGeometry( func, slices, stacks ) { + + Geometry.call( this ); + + this.type = 'ParametricGeometry'; + + this.parameters = { + func: func, + slices: slices, + stacks: stacks + }; + + this.fromBufferGeometry( new ParametricBufferGeometry( func, slices, stacks ) ); + this.mergeVertices(); + +} + +ParametricGeometry.prototype = Object.create( Geometry.prototype ); +ParametricGeometry.prototype.constructor = ParametricGeometry; + +/** + * @author Mugen87 / https://github.com/Mugen87 + * + * Parametric Surfaces Geometry + * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 + */ + +function ParametricBufferGeometry( func, slices, stacks ) { + + BufferGeometry.call( this ); + + this.type = 'ParametricBufferGeometry'; + + this.parameters = { + func: func, + slices: slices, + stacks: stacks + }; + + // buffers + + var indices = []; + var vertices = []; + var uvs = []; + + var i, j; + + // generate vertices and uvs + + var sliceCount = slices + 1; + + for ( i = 0; i <= stacks; i ++ ) { + + var v = i / stacks; + + for ( j = 0; j <= slices; j ++ ) { + + var u = j / slices; + + var p = func( u, v ); + vertices.push( p.x, p.y, p.z ); + + uvs.push( u, v ); + + } + + } + + // generate indices + + for ( i = 0; i < stacks; i ++ ) { + + for ( j = 0; j < slices; j ++ ) { + + var a = i * sliceCount + j; + var b = i * sliceCount + j + 1; + var c = ( i + 1 ) * sliceCount + j + 1; + var d = ( i + 1 ) * sliceCount + j; + + // faces one and two + + indices.push( a, b, d ); + indices.push( b, c, d ); + + } + + } + + // build geometry + + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + + // generate normals + + this.computeVertexNormals(); + +} + +ParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +ParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry; + +/** + * @author clockworkgeek / https://github.com/clockworkgeek + * @author timothypratley / https://github.com/timothypratley + * @author WestLangley / http://github.com/WestLangley +*/ + +function PolyhedronGeometry( vertices, indices, radius, detail ) { + + Geometry.call( this ); + + this.type = 'PolyhedronGeometry'; + + this.parameters = { + vertices: vertices, + indices: indices, + radius: radius, + detail: detail + }; + + this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) ); + this.mergeVertices(); + +} + +PolyhedronGeometry.prototype = Object.create( Geometry.prototype ); +PolyhedronGeometry.prototype.constructor = PolyhedronGeometry; + +/** + * @author Mugen87 / https://github.com/Mugen87 + */ + +function PolyhedronBufferGeometry( vertices, indices, radius, detail ) { + + BufferGeometry.call( this ); + + this.type = 'PolyhedronBufferGeometry'; + + this.parameters = { + vertices: vertices, + indices: indices, + radius: radius, + detail: detail + }; + + radius = radius || 1; + detail = detail || 0; + + // default buffer data + + var vertexBuffer = []; + var uvBuffer = []; + + // the subdivision creates the vertex buffer data + + subdivide( detail ); + + // all vertices should lie on a conceptual sphere with a given radius + + appplyRadius( radius ); + + // finally, create the uv data + + generateUVs(); + + // build non-indexed geometry + + this.addAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) ); + this.normalizeNormals(); + + // helper functions + + function subdivide( detail ) { + + var a = new Vector3(); + var b = new Vector3(); + var c = new Vector3(); + + // iterate over all faces and apply a subdivison with the given detail value + + for ( var i = 0; i < indices.length; i += 3 ) { + + // get the vertices of the face + + getVertexByIndex( indices[ i + 0 ], a ); + getVertexByIndex( indices[ i + 1 ], b ); + getVertexByIndex( indices[ i + 2 ], c ); + + // perform subdivision + + subdivideFace( a, b, c, detail ); + + } + + } + + function subdivideFace( a, b, c, detail ) { + + var cols = Math.pow( 2, detail ); + + // we use this multidimensional array as a data structure for creating the subdivision + + var v = []; + + var i, j; + + // construct all of the vertices for this subdivision + + for ( i = 0; i <= cols; i ++ ) { + + v[ i ] = []; + + var aj = a.clone().lerp( c, i / cols ); + var bj = b.clone().lerp( c, i / cols ); + + var rows = cols - i; + + for ( j = 0; j <= rows; j ++ ) { + + if ( j === 0 && i === cols ) { + + v[ i ][ j ] = aj; + + } else { + + v[ i ][ j ] = aj.clone().lerp( bj, j / rows ); + + } + + } + + } + + // construct all of the faces + + for ( i = 0; i < cols; i ++ ) { + + for ( j = 0; j < 2 * ( cols - i ) - 1; j ++ ) { + + var k = Math.floor( j / 2 ); + + if ( j % 2 === 0 ) { + + pushVertex( v[ i ][ k + 1 ] ); + pushVertex( v[ i + 1 ][ k ] ); + pushVertex( v[ i ][ k ] ); + + } else { + + pushVertex( v[ i ][ k + 1 ] ); + pushVertex( v[ i + 1 ][ k + 1 ] ); + pushVertex( v[ i + 1 ][ k ] ); + + } + + } + + } + + } + + function appplyRadius( radius ) { + + var vertex = new Vector3(); + + // iterate over the entire buffer and apply the radius to each vertex + + for ( var i = 0; i < vertexBuffer.length; i += 3 ) { + + vertex.x = vertexBuffer[ i + 0 ]; + vertex.y = vertexBuffer[ i + 1 ]; + vertex.z = vertexBuffer[ i + 2 ]; + + vertex.normalize().multiplyScalar( radius ); + + vertexBuffer[ i + 0 ] = vertex.x; + vertexBuffer[ i + 1 ] = vertex.y; + vertexBuffer[ i + 2 ] = vertex.z; + + } + + } + + function generateUVs() { + + var vertex = new Vector3(); + + for ( var i = 0; i < vertexBuffer.length; i += 3 ) { + + vertex.x = vertexBuffer[ i + 0 ]; + vertex.y = vertexBuffer[ i + 1 ]; + vertex.z = vertexBuffer[ i + 2 ]; + + var u = azimuth( vertex ) / 2 / Math.PI + 0.5; + var v = inclination( vertex ) / Math.PI + 0.5; + uvBuffer.push( u, 1 - v ); + + } + + correctUVs(); + + correctSeam(); + + } + + function correctSeam() { + + // handle case when face straddles the seam, see #3269 + + for ( var i = 0; i < uvBuffer.length; i += 6 ) { + + // uv data of a single face + + var x0 = uvBuffer[ i + 0 ]; + var x1 = uvBuffer[ i + 2 ]; + var x2 = uvBuffer[ i + 4 ]; + + var max = Math.max( x0, x1, x2 ); + var min = Math.min( x0, x1, x2 ); + + // 0.9 is somewhat arbitrary + + if ( max > 0.9 && min < 0.1 ) { + + if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1; + if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1; + if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1; + + } + + } + + } + + function pushVertex( vertex ) { + + vertexBuffer.push( vertex.x, vertex.y, vertex.z ); + + } + + function getVertexByIndex( index, vertex ) { + + var stride = index * 3; + + vertex.x = vertices[ stride + 0 ]; + vertex.y = vertices[ stride + 1 ]; + vertex.z = vertices[ stride + 2 ]; + + } + + function correctUVs() { + + var a = new Vector3(); + var b = new Vector3(); + var c = new Vector3(); + + var centroid = new Vector3(); + + var uvA = new Vector2(); + var uvB = new Vector2(); + var uvC = new Vector2(); + + for ( var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) { + + a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] ); + b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] ); + c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] ); + + uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] ); + uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] ); + uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] ); + + centroid.copy( a ).add( b ).add( c ).divideScalar( 3 ); + + var azi = azimuth( centroid ); + + correctUV( uvA, j + 0, a, azi ); + correctUV( uvB, j + 2, b, azi ); + correctUV( uvC, j + 4, c, azi ); + + } + + } + + function correctUV( uv, stride, vector, azimuth ) { + + if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) { + + uvBuffer[ stride ] = uv.x - 1; + + } + + if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) { + + uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5; + + } + + } + + // Angle around the Y axis, counter-clockwise when looking from above. + + function azimuth( vector ) { + + return Math.atan2( vector.z, - vector.x ); + + } + + + // Angle above the XZ plane. + + function inclination( vector ) { + + return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); + + } + +} + +PolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry; + +/** + * @author timothypratley / https://github.com/timothypratley + */ + +function TetrahedronGeometry( radius, detail ) { + + Geometry.call( this ); + + this.type = 'TetrahedronGeometry'; + + this.parameters = { + radius: radius, + detail: detail + }; + + this.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) ); + this.mergeVertices(); + +} + +TetrahedronGeometry.prototype = Object.create( Geometry.prototype ); +TetrahedronGeometry.prototype.constructor = TetrahedronGeometry; + +/** + * @author Mugen87 / https://github.com/Mugen87 + */ + +function TetrahedronBufferGeometry( radius, detail ) { + + var vertices = [ + 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 + ]; + + var indices = [ + 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 + ]; + + PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); + + this.type = 'TetrahedronBufferGeometry'; + + this.parameters = { + radius: radius, + detail: detail + }; + +} + +TetrahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); +TetrahedronBufferGeometry.prototype.constructor = TetrahedronBufferGeometry; + +/** + * @author timothypratley / https://github.com/timothypratley + */ + +function OctahedronGeometry( radius, detail ) { + + Geometry.call( this ); + + this.type = 'OctahedronGeometry'; + + this.parameters = { + radius: radius, + detail: detail + }; + + this.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) ); + this.mergeVertices(); + +} + +OctahedronGeometry.prototype = Object.create( Geometry.prototype ); +OctahedronGeometry.prototype.constructor = OctahedronGeometry; + +/** + * @author Mugen87 / https://github.com/Mugen87 + */ + +function OctahedronBufferGeometry( radius, detail ) { + + var vertices = [ + 1, 0, 0, - 1, 0, 0, 0, 1, 0, 0, - 1, 0, 0, 0, 1, 0, 0, - 1 + ]; + + var indices = [ + 0, 2, 4, 0, 4, 3, 0, 3, 5, 0, 5, 2, 1, 2, 5, 1, 5, 3, 1, 3, 4, 1, 4, 2 + ]; + + PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); + + this.type = 'OctahedronBufferGeometry'; + + this.parameters = { + radius: radius, + detail: detail + }; + +} + +OctahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); +OctahedronBufferGeometry.prototype.constructor = OctahedronBufferGeometry; + +/** + * @author timothypratley / https://github.com/timothypratley + */ + +function IcosahedronGeometry( radius, detail ) { + + Geometry.call( this ); + + this.type = 'IcosahedronGeometry'; + + this.parameters = { + radius: radius, + detail: detail + }; + + this.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) ); + this.mergeVertices(); + +} + +IcosahedronGeometry.prototype = Object.create( Geometry.prototype ); +IcosahedronGeometry.prototype.constructor = IcosahedronGeometry; + +/** + * @author Mugen87 / https://github.com/Mugen87 + */ + +function IcosahedronBufferGeometry( radius, detail ) { + + var t = ( 1 + Math.sqrt( 5 ) ) / 2; + + var vertices = [ + - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0, + 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, + t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1 + ]; + + var indices = [ + 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11, + 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8, + 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9, + 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1 + ]; + + PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); + + this.type = 'IcosahedronBufferGeometry'; + + this.parameters = { + radius: radius, + detail: detail + }; + +} + +IcosahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); +IcosahedronBufferGeometry.prototype.constructor = IcosahedronBufferGeometry; + +/** + * @author Abe Pazos / https://hamoid.com + */ + +function DodecahedronGeometry( radius, detail ) { + + Geometry.call( this ); + + this.type = 'DodecahedronGeometry'; + + this.parameters = { + radius: radius, + detail: detail + }; + + this.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) ); + this.mergeVertices(); + +} + +DodecahedronGeometry.prototype = Object.create( Geometry.prototype ); +DodecahedronGeometry.prototype.constructor = DodecahedronGeometry; + +/** + * @author Mugen87 / https://github.com/Mugen87 + */ + +function DodecahedronBufferGeometry( radius, detail ) { + + var t = ( 1 + Math.sqrt( 5 ) ) / 2; + var r = 1 / t; + + var vertices = [ + + // (±1, ±1, ±1) + - 1, - 1, - 1, - 1, - 1, 1, + - 1, 1, - 1, - 1, 1, 1, + 1, - 1, - 1, 1, - 1, 1, + 1, 1, - 1, 1, 1, 1, + + // (0, ±1/φ, ±φ) + 0, - r, - t, 0, - r, t, + 0, r, - t, 0, r, t, + + // (±1/φ, ±φ, 0) + - r, - t, 0, - r, t, 0, + r, - t, 0, r, t, 0, + + // (±φ, 0, ±1/φ) + - t, 0, - r, t, 0, - r, + - t, 0, r, t, 0, r + ]; + + var indices = [ + 3, 11, 7, 3, 7, 15, 3, 15, 13, + 7, 19, 17, 7, 17, 6, 7, 6, 15, + 17, 4, 8, 17, 8, 10, 17, 10, 6, + 8, 0, 16, 8, 16, 2, 8, 2, 10, + 0, 12, 1, 0, 1, 18, 0, 18, 16, + 6, 10, 2, 6, 2, 13, 6, 13, 15, + 2, 16, 18, 2, 18, 3, 2, 3, 13, + 18, 1, 9, 18, 9, 11, 18, 11, 3, + 4, 14, 12, 4, 12, 0, 4, 0, 8, + 11, 9, 5, 11, 5, 19, 11, 19, 7, + 19, 5, 14, 19, 14, 4, 19, 4, 17, + 1, 12, 14, 1, 14, 5, 1, 5, 9 + ]; + + PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); + + this.type = 'DodecahedronBufferGeometry'; + + this.parameters = { + radius: radius, + detail: detail + }; + +} + +DodecahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); +DodecahedronBufferGeometry.prototype.constructor = DodecahedronBufferGeometry; + +/** + * @author oosmoxiecode / https://github.com/oosmoxiecode + * @author WestLangley / https://github.com/WestLangley + * @author zz85 / https://github.com/zz85 + * @author miningold / https://github.com/miningold + * @author jonobr1 / https://github.com/jonobr1 + * + * Creates a tube which extrudes along a 3d spline. + */ + +function TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) { + + Geometry.call( this ); + + this.type = 'TubeGeometry'; + + this.parameters = { + path: path, + tubularSegments: tubularSegments, + radius: radius, + radialSegments: radialSegments, + closed: closed + }; + + if ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' ); + + var bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ); + + // expose internals + + this.tangents = bufferGeometry.tangents; + this.normals = bufferGeometry.normals; + this.binormals = bufferGeometry.binormals; + + // create geometry + + this.fromBufferGeometry( bufferGeometry ); + this.mergeVertices(); + +} + +TubeGeometry.prototype = Object.create( Geometry.prototype ); +TubeGeometry.prototype.constructor = TubeGeometry; + +/** + * @author Mugen87 / https://github.com/Mugen87 + */ + +function TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) { + + BufferGeometry.call( this ); + + this.type = 'TubeBufferGeometry'; + + this.parameters = { + path: path, + tubularSegments: tubularSegments, + radius: radius, + radialSegments: radialSegments, + closed: closed + }; + + tubularSegments = tubularSegments || 64; + radius = radius || 1; + radialSegments = radialSegments || 8; + closed = closed || false; + + var frames = path.computeFrenetFrames( tubularSegments, closed ); + + // expose internals + + this.tangents = frames.tangents; + this.normals = frames.normals; + this.binormals = frames.binormals; + + // helper variables + + var vertex = new Vector3(); + var normal = new Vector3(); + var uv = new Vector2(); + + var i, j; + + // buffer + + var vertices = []; + var normals = []; + var uvs = []; + var indices = []; + + // create buffer data + + generateBufferData(); + + // build geometry + + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + + // functions + + function generateBufferData() { + + for ( i = 0; i < tubularSegments; i ++ ) { + + generateSegment( i ); + + } + + // if the geometry is not closed, generate the last row of vertices and normals + // at the regular position on the given path + // + // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ) + + generateSegment( ( closed === false ) ? tubularSegments : 0 ); + + // uvs are generated in a separate function. + // this makes it easy compute correct values for closed geometries + + generateUVs(); + + // finally create faces + + generateIndices(); + + } + + function generateSegment( i ) { + + // we use getPointAt to sample evenly distributed points from the given path + + var P = path.getPointAt( i / tubularSegments ); + + // retrieve corresponding normal and binormal + + var N = frames.normals[ i ]; + var B = frames.binormals[ i ]; + + // generate normals and vertices for the current segment + + for ( j = 0; j <= radialSegments; j ++ ) { + + var v = j / radialSegments * Math.PI * 2; + + var sin = Math.sin( v ); + var cos = - Math.cos( v ); + + // normal + + normal.x = ( cos * N.x + sin * B.x ); + normal.y = ( cos * N.y + sin * B.y ); + normal.z = ( cos * N.z + sin * B.z ); + normal.normalize(); + + normals.push( normal.x, normal.y, normal.z ); + + // vertex + + vertex.x = P.x + radius * normal.x; + vertex.y = P.y + radius * normal.y; + vertex.z = P.z + radius * normal.z; + + vertices.push( vertex.x, vertex.y, vertex.z ); + + } + + } + + function generateIndices() { + + for ( j = 1; j <= tubularSegments; j ++ ) { + + for ( i = 1; i <= radialSegments; i ++ ) { + + var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); + var b = ( radialSegments + 1 ) * j + ( i - 1 ); + var c = ( radialSegments + 1 ) * j + i; + var d = ( radialSegments + 1 ) * ( j - 1 ) + i; + + // faces + + indices.push( a, b, d ); + indices.push( b, c, d ); + + } + + } + + } + + function generateUVs() { + + for ( i = 0; i <= tubularSegments; i ++ ) { + + for ( j = 0; j <= radialSegments; j ++ ) { + + uv.x = i / tubularSegments; + uv.y = j / radialSegments; + + uvs.push( uv.x, uv.y ); + + } + + } + + } + +} + +TubeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +TubeBufferGeometry.prototype.constructor = TubeBufferGeometry; + +/** + * @author oosmoxiecode + */ + +function TorusKnotGeometry( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) { + + Geometry.call( this ); + + this.type = 'TorusKnotGeometry'; + + this.parameters = { + radius: radius, + tube: tube, + tubularSegments: tubularSegments, + radialSegments: radialSegments, + p: p, + q: q + }; + + if ( heightScale !== undefined ) console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' ); + + this.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) ); + this.mergeVertices(); + +} + +TorusKnotGeometry.prototype = Object.create( Geometry.prototype ); +TorusKnotGeometry.prototype.constructor = TorusKnotGeometry; + +/** + * @author Mugen87 / https://github.com/Mugen87 + * see: http://www.blackpawn.com/texts/pqtorus/ + */ + +function TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) { + + BufferGeometry.call( this ); + + this.type = 'TorusKnotBufferGeometry'; + + this.parameters = { + radius: radius, + tube: tube, + tubularSegments: tubularSegments, + radialSegments: radialSegments, + p: p, + q: q + }; + + radius = radius || 100; + tube = tube || 40; + tubularSegments = Math.floor( tubularSegments ) || 64; + radialSegments = Math.floor( radialSegments ) || 8; + p = p || 2; + q = q || 3; + + // buffers + + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; + + // helper variables + + var i, j; + + var vertex = new Vector3(); + var normal = new Vector3(); + var uv = new Vector2(); + + var P1 = new Vector3(); + var P2 = new Vector3(); + + var B = new Vector3(); + var T = new Vector3(); + var N = new Vector3(); + + // generate vertices, normals and uvs + + for ( i = 0; i <= tubularSegments; ++ i ) { + + // the radian "u" is used to calculate the position on the torus curve of the current tubular segement + + var u = i / tubularSegments * p * Math.PI * 2; + + // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead. + // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions + + calculatePositionOnCurve( u, p, q, radius, P1 ); + calculatePositionOnCurve( u + 0.01, p, q, radius, P2 ); + + // calculate orthonormal basis + + T.subVectors( P2, P1 ); + N.addVectors( P2, P1 ); + B.crossVectors( T, N ); + N.crossVectors( B, T ); + + // normalize B, N. T can be ignored, we don't use it + + B.normalize(); + N.normalize(); + + for ( j = 0; j <= radialSegments; ++ j ) { + + // now calculate the vertices. they are nothing more than an extrusion of the torus curve. + // because we extrude a shape in the xy-plane, there is no need to calculate a z-value. + + var v = j / radialSegments * Math.PI * 2; + var cx = - tube * Math.cos( v ); + var cy = tube * Math.sin( v ); + + // now calculate the final vertex position. + // first we orient the extrusion with our basis vectos, then we add it to the current position on the curve + + vertex.x = P1.x + ( cx * N.x + cy * B.x ); + vertex.y = P1.y + ( cx * N.y + cy * B.y ); + vertex.z = P1.z + ( cx * N.z + cy * B.z ); + + vertices.push( vertex.x, vertex.y, vertex.z ); + + // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal) + + normal.subVectors( vertex, P1 ).normalize(); + + normals.push( normal.x, normal.y, normal.z ); + + // uv + + uvs.push( i / tubularSegments ); + uvs.push( j / radialSegments ); + + } + + } + + // generate indices + + for ( j = 1; j <= tubularSegments; j ++ ) { + + for ( i = 1; i <= radialSegments; i ++ ) { + + // indices + + var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); + var b = ( radialSegments + 1 ) * j + ( i - 1 ); + var c = ( radialSegments + 1 ) * j + i; + var d = ( radialSegments + 1 ) * ( j - 1 ) + i; + + // faces + + indices.push( a, b, d ); + indices.push( b, c, d ); + + } + + } + + // build geometry + + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + + // this function calculates the current position on the torus curve + + function calculatePositionOnCurve( u, p, q, radius, position ) { + + var cu = Math.cos( u ); + var su = Math.sin( u ); + var quOverP = q / p * u; + var cs = Math.cos( quOverP ); + + position.x = radius * ( 2 + cs ) * 0.5 * cu; + position.y = radius * ( 2 + cs ) * su * 0.5; + position.z = radius * Math.sin( quOverP ) * 0.5; + + } + +} + +TorusKnotBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +TorusKnotBufferGeometry.prototype.constructor = TorusKnotBufferGeometry; + +/** + * @author oosmoxiecode + * @author mrdoob / http://mrdoob.com/ + * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3DLite/src/away3dlite/primitives/Torus.as?r=2888 + */ + +function TorusGeometry( radius, tube, radialSegments, tubularSegments, arc ) { + + Geometry.call( this ); + + this.type = 'TorusGeometry'; + + this.parameters = { + radius: radius, + tube: tube, + radialSegments: radialSegments, + tubularSegments: tubularSegments, + arc: arc + }; + + this.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) ); + +} + +TorusGeometry.prototype = Object.create( Geometry.prototype ); +TorusGeometry.prototype.constructor = TorusGeometry; + +/** + * @author Mugen87 / https://github.com/Mugen87 + */ + +function TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) { + + BufferGeometry.call( this ); + + this.type = 'TorusBufferGeometry'; + + this.parameters = { + radius: radius, + tube: tube, + radialSegments: radialSegments, + tubularSegments: tubularSegments, + arc: arc + }; + + radius = radius || 100; + tube = tube || 40; + radialSegments = Math.floor( radialSegments ) || 8; + tubularSegments = Math.floor( tubularSegments ) || 6; + arc = arc || Math.PI * 2; + + // buffers + + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; + + // helper variables + + var center = new Vector3(); + var vertex = new Vector3(); + var normal = new Vector3(); + + var j, i; + + // generate vertices, normals and uvs + + for ( j = 0; j <= radialSegments; j ++ ) { + + for ( i = 0; i <= tubularSegments; i ++ ) { + + var u = i / tubularSegments * arc; + var v = j / radialSegments * Math.PI * 2; + + // vertex + + vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u ); + vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u ); + vertex.z = tube * Math.sin( v ); + + vertices.push( vertex.x, vertex.y, vertex.z ); + + // normal + + center.x = radius * Math.cos( u ); + center.y = radius * Math.sin( u ); + normal.subVectors( vertex, center ).normalize(); + + normals.push( normal.x, normal.y, normal.z ); + + // uv + + uvs.push( i / tubularSegments ); + uvs.push( j / radialSegments ); + + } + + } + + // generate indices + + for ( j = 1; j <= radialSegments; j ++ ) { + + for ( i = 1; i <= tubularSegments; i ++ ) { + + // indices + + var a = ( tubularSegments + 1 ) * j + i - 1; + var b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1; + var c = ( tubularSegments + 1 ) * ( j - 1 ) + i; + var d = ( tubularSegments + 1 ) * j + i; + + // faces + + indices.push( a, b, d ); + indices.push( b, c, d ); + + } + + } + + // build geometry + + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + +} + +TorusBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +TorusBufferGeometry.prototype.constructor = TorusBufferGeometry; + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + */ + +var ShapeUtils = { + + // calculate area of the contour polygon + + area: function ( contour ) { + + var n = contour.length; + var a = 0.0; + + for ( var p = n - 1, q = 0; q < n; p = q ++ ) { + + a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; + + } + + return a * 0.5; + + }, + + triangulate: ( function () { + + /** + * This code is a quick port of code written in C++ which was submitted to + * flipcode.com by John W. Ratcliff // July 22, 2000 + * See original code and more information here: + * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml + * + * ported to actionscript by Zevan Rosser + * www.actionsnippet.com + * + * ported to javascript by Joshua Koo + * http://www.lab4games.net/zz85/blog + * + */ + + function snip( contour, u, v, w, n, verts ) { + + var p; + var ax, ay, bx, by; + var cx, cy, px, py; + + ax = contour[ verts[ u ] ].x; + ay = contour[ verts[ u ] ].y; + + bx = contour[ verts[ v ] ].x; + by = contour[ verts[ v ] ].y; + + cx = contour[ verts[ w ] ].x; + cy = contour[ verts[ w ] ].y; + + if ( ( bx - ax ) * ( cy - ay ) - ( by - ay ) * ( cx - ax ) <= 0 ) return false; + + var aX, aY, bX, bY, cX, cY; + var apx, apy, bpx, bpy, cpx, cpy; + var cCROSSap, bCROSScp, aCROSSbp; + + aX = cx - bx; aY = cy - by; + bX = ax - cx; bY = ay - cy; + cX = bx - ax; cY = by - ay; + + for ( p = 0; p < n; p ++ ) { + + px = contour[ verts[ p ] ].x; + py = contour[ verts[ p ] ].y; + + if ( ( ( px === ax ) && ( py === ay ) ) || + ( ( px === bx ) && ( py === by ) ) || + ( ( px === cx ) && ( py === cy ) ) ) continue; + + apx = px - ax; apy = py - ay; + bpx = px - bx; bpy = py - by; + cpx = px - cx; cpy = py - cy; + + // see if p is inside triangle abc + + aCROSSbp = aX * bpy - aY * bpx; + cCROSSap = cX * apy - cY * apx; + bCROSScp = bX * cpy - bY * cpx; + + if ( ( aCROSSbp >= - Number.EPSILON ) && ( bCROSScp >= - Number.EPSILON ) && ( cCROSSap >= - Number.EPSILON ) ) return false; + + } + + return true; + + } + + // takes in an contour array and returns + + return function triangulate( contour, indices ) { + + var n = contour.length; + + if ( n < 3 ) return null; + + var result = [], + verts = [], + vertIndices = []; + + /* we want a counter-clockwise polygon in verts */ + + var u, v, w; + + if ( ShapeUtils.area( contour ) > 0.0 ) { + + for ( v = 0; v < n; v ++ ) verts[ v ] = v; + + } else { + + for ( v = 0; v < n; v ++ ) verts[ v ] = ( n - 1 ) - v; + + } + + var nv = n; + + /* remove nv - 2 vertices, creating 1 triangle every time */ + + var count = 2 * nv; /* error detection */ + + for ( v = nv - 1; nv > 2; ) { + + /* if we loop, it is probably a non-simple polygon */ + + if ( ( count -- ) <= 0 ) { + + //** Triangulate: ERROR - probable bad polygon! + + //throw ( "Warning, unable to triangulate polygon!" ); + //return null; + // Sometimes warning is fine, especially polygons are triangulated in reverse. + console.warn( 'THREE.ShapeUtils: Unable to triangulate polygon! in triangulate()' ); + + if ( indices ) return vertIndices; + return result; + + } + + /* three consecutive vertices in current polygon, */ + + u = v; if ( nv <= u ) u = 0; /* previous */ + v = u + 1; if ( nv <= v ) v = 0; /* new v */ + w = v + 1; if ( nv <= w ) w = 0; /* next */ + + if ( snip( contour, u, v, w, nv, verts ) ) { + + var a, b, c, s, t; + + /* true names of the vertices */ + + a = verts[ u ]; + b = verts[ v ]; + c = verts[ w ]; + + /* output Triangle */ + + result.push( [ contour[ a ], + contour[ b ], + contour[ c ] ] ); + + + vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] ); + + /* remove v from the remaining polygon */ + + for ( s = v, t = v + 1; t < nv; s ++, t ++ ) { + + verts[ s ] = verts[ t ]; + + } + + nv --; + + /* reset error detection counter */ + + count = 2 * nv; + + } + + } + + if ( indices ) return vertIndices; + return result; + + } + + } )(), + + triangulateShape: function ( contour, holes ) { + + function removeDupEndPts(points) { + + var l = points.length; + + if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) { + + points.pop(); + + } + + } + + removeDupEndPts( contour ); + holes.forEach( removeDupEndPts ); + + function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) { + + // inOtherPt needs to be collinear to the inSegment + if ( inSegPt1.x !== inSegPt2.x ) { + + if ( inSegPt1.x < inSegPt2.x ) { + + return ( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) ); + + } else { + + return ( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) ); + + } + + } else { + + if ( inSegPt1.y < inSegPt2.y ) { + + return ( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) ); + + } else { + + return ( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) ); + + } + + } + + } + + function intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) { + + var seg1dx = inSeg1Pt2.x - inSeg1Pt1.x, seg1dy = inSeg1Pt2.y - inSeg1Pt1.y; + var seg2dx = inSeg2Pt2.x - inSeg2Pt1.x, seg2dy = inSeg2Pt2.y - inSeg2Pt1.y; + + var seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x; + var seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y; + + var limit = seg1dy * seg2dx - seg1dx * seg2dy; + var perpSeg1 = seg1dy * seg1seg2dx - seg1dx * seg1seg2dy; + + if ( Math.abs( limit ) > Number.EPSILON ) { + + // not parallel + + var perpSeg2; + if ( limit > 0 ) { + + if ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) return []; + perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; + if ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) return []; + + } else { + + if ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) return []; + perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; + if ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) return []; + + } + + // i.e. to reduce rounding errors + // intersection at endpoint of segment#1? + if ( perpSeg2 === 0 ) { + + if ( ( inExcludeAdjacentSegs ) && + ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) ) return []; + return [ inSeg1Pt1 ]; + + } + if ( perpSeg2 === limit ) { + + if ( ( inExcludeAdjacentSegs ) && + ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) ) return []; + return [ inSeg1Pt2 ]; + + } + // intersection at endpoint of segment#2? + if ( perpSeg1 === 0 ) return [ inSeg2Pt1 ]; + if ( perpSeg1 === limit ) return [ inSeg2Pt2 ]; + + // return real intersection point + var factorSeg1 = perpSeg2 / limit; + return [ { x: inSeg1Pt1.x + factorSeg1 * seg1dx, + y: inSeg1Pt1.y + factorSeg1 * seg1dy } ]; + + } else { + + // parallel or collinear + if ( ( perpSeg1 !== 0 ) || + ( seg2dy * seg1seg2dx !== seg2dx * seg1seg2dy ) ) return []; + + // they are collinear or degenerate + var seg1Pt = ( ( seg1dx === 0 ) && ( seg1dy === 0 ) ); // segment1 is just a point? + var seg2Pt = ( ( seg2dx === 0 ) && ( seg2dy === 0 ) ); // segment2 is just a point? + // both segments are points + if ( seg1Pt && seg2Pt ) { + + if ( ( inSeg1Pt1.x !== inSeg2Pt1.x ) || + ( inSeg1Pt1.y !== inSeg2Pt1.y ) ) return []; // they are distinct points + return [ inSeg1Pt1 ]; // they are the same point + + } + // segment#1 is a single point + if ( seg1Pt ) { + + if ( ! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) ) return []; // but not in segment#2 + return [ inSeg1Pt1 ]; + + } + // segment#2 is a single point + if ( seg2Pt ) { + + if ( ! point_in_segment_2D_colin( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1 ) ) return []; // but not in segment#1 + return [ inSeg2Pt1 ]; + + } + + // they are collinear segments, which might overlap + var seg1min, seg1max, seg1minVal, seg1maxVal; + var seg2min, seg2max, seg2minVal, seg2maxVal; + if ( seg1dx !== 0 ) { + + // the segments are NOT on a vertical line + if ( inSeg1Pt1.x < inSeg1Pt2.x ) { + + seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x; + seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x; + + } else { + + seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x; + seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x; + + } + if ( inSeg2Pt1.x < inSeg2Pt2.x ) { + + seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x; + seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x; + + } else { + + seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x; + seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x; + + } + + } else { + + // the segments are on a vertical line + if ( inSeg1Pt1.y < inSeg1Pt2.y ) { + + seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y; + seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y; + + } else { + + seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y; + seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y; + + } + if ( inSeg2Pt1.y < inSeg2Pt2.y ) { + + seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y; + seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y; + + } else { + + seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y; + seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y; + + } + + } + if ( seg1minVal <= seg2minVal ) { + + if ( seg1maxVal < seg2minVal ) return []; + if ( seg1maxVal === seg2minVal ) { + + if ( inExcludeAdjacentSegs ) return []; + return [ seg2min ]; + + } + if ( seg1maxVal <= seg2maxVal ) return [ seg2min, seg1max ]; + return [ seg2min, seg2max ]; + + } else { + + if ( seg1minVal > seg2maxVal ) return []; + if ( seg1minVal === seg2maxVal ) { + + if ( inExcludeAdjacentSegs ) return []; + return [ seg1min ]; + + } + if ( seg1maxVal <= seg2maxVal ) return [ seg1min, seg1max ]; + return [ seg1min, seg2max ]; + + } + + } + + } + + function isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) { + + // The order of legs is important + + // translation of all points, so that Vertex is at (0,0) + var legFromPtX = inLegFromPt.x - inVertex.x, legFromPtY = inLegFromPt.y - inVertex.y; + var legToPtX = inLegToPt.x - inVertex.x, legToPtY = inLegToPt.y - inVertex.y; + var otherPtX = inOtherPt.x - inVertex.x, otherPtY = inOtherPt.y - inVertex.y; + + // main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg. + var from2toAngle = legFromPtX * legToPtY - legFromPtY * legToPtX; + var from2otherAngle = legFromPtX * otherPtY - legFromPtY * otherPtX; + + if ( Math.abs( from2toAngle ) > Number.EPSILON ) { + + // angle != 180 deg. + + var other2toAngle = otherPtX * legToPtY - otherPtY * legToPtX; + // console.log( "from2to: " + from2toAngle + ", from2other: " + from2otherAngle + ", other2to: " + other2toAngle ); + + if ( from2toAngle > 0 ) { + + // main angle < 180 deg. + return ( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) ); + + } else { + + // main angle > 180 deg. + return ( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) ); + + } + + } else { + + // angle == 180 deg. + // console.log( "from2to: 180 deg., from2other: " + from2otherAngle ); + return ( from2otherAngle > 0 ); + + } + + } + + + function removeHoles( contour, holes ) { + + var shape = contour.concat(); // work on this shape + var hole; + + function isCutLineInsideAngles( inShapeIdx, inHoleIdx ) { + + // Check if hole point lies within angle around shape point + var lastShapeIdx = shape.length - 1; + + var prevShapeIdx = inShapeIdx - 1; + if ( prevShapeIdx < 0 ) prevShapeIdx = lastShapeIdx; + + var nextShapeIdx = inShapeIdx + 1; + if ( nextShapeIdx > lastShapeIdx ) nextShapeIdx = 0; + + var insideAngle = isPointInsideAngle( shape[ inShapeIdx ], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[ inHoleIdx ] ); + if ( ! insideAngle ) { + + // console.log( "Vertex (Shape): " + inShapeIdx + ", Point: " + hole[inHoleIdx].x + "/" + hole[inHoleIdx].y ); + return false; + + } + + // Check if shape point lies within angle around hole point + var lastHoleIdx = hole.length - 1; + + var prevHoleIdx = inHoleIdx - 1; + if ( prevHoleIdx < 0 ) prevHoleIdx = lastHoleIdx; + + var nextHoleIdx = inHoleIdx + 1; + if ( nextHoleIdx > lastHoleIdx ) nextHoleIdx = 0; + + insideAngle = isPointInsideAngle( hole[ inHoleIdx ], hole[ prevHoleIdx ], hole[ nextHoleIdx ], shape[ inShapeIdx ] ); + if ( ! insideAngle ) { + + // console.log( "Vertex (Hole): " + inHoleIdx + ", Point: " + shape[inShapeIdx].x + "/" + shape[inShapeIdx].y ); + return false; + + } + + return true; + + } + + function intersectsShapeEdge( inShapePt, inHolePt ) { + + // checks for intersections with shape edges + var sIdx, nextIdx, intersection; + for ( sIdx = 0; sIdx < shape.length; sIdx ++ ) { + + nextIdx = sIdx + 1; nextIdx %= shape.length; + intersection = intersect_segments_2D( inShapePt, inHolePt, shape[ sIdx ], shape[ nextIdx ], true ); + if ( intersection.length > 0 ) return true; + + } + + return false; + + } + + var indepHoles = []; + + function intersectsHoleEdge( inShapePt, inHolePt ) { + + // checks for intersections with hole edges + var ihIdx, chkHole, + hIdx, nextIdx, intersection; + for ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx ++ ) { + + chkHole = holes[ indepHoles[ ihIdx ]]; + for ( hIdx = 0; hIdx < chkHole.length; hIdx ++ ) { + + nextIdx = hIdx + 1; nextIdx %= chkHole.length; + intersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[ hIdx ], chkHole[ nextIdx ], true ); + if ( intersection.length > 0 ) return true; + + } + + } + return false; + + } + + var holeIndex, shapeIndex, + shapePt, holePt, + holeIdx, cutKey, failedCuts = [], + tmpShape1, tmpShape2, + tmpHole1, tmpHole2; + + for ( var h = 0, hl = holes.length; h < hl; h ++ ) { + + indepHoles.push( h ); + + } + + var minShapeIndex = 0; + var counter = indepHoles.length * 2; + while ( indepHoles.length > 0 ) { + + counter --; + if ( counter < 0 ) { + + console.log( "Infinite Loop! Holes left:" + indepHoles.length + ", Probably Hole outside Shape!" ); + break; + + } + + // search for shape-vertex and hole-vertex, + // which can be connected without intersections + for ( shapeIndex = minShapeIndex; shapeIndex < shape.length; shapeIndex ++ ) { + + shapePt = shape[ shapeIndex ]; + holeIndex = - 1; + + // search for hole which can be reached without intersections + for ( var h = 0; h < indepHoles.length; h ++ ) { + + holeIdx = indepHoles[ h ]; + + // prevent multiple checks + cutKey = shapePt.x + ":" + shapePt.y + ":" + holeIdx; + if ( failedCuts[ cutKey ] !== undefined ) continue; + + hole = holes[ holeIdx ]; + for ( var h2 = 0; h2 < hole.length; h2 ++ ) { + + holePt = hole[ h2 ]; + if ( ! isCutLineInsideAngles( shapeIndex, h2 ) ) continue; + if ( intersectsShapeEdge( shapePt, holePt ) ) continue; + if ( intersectsHoleEdge( shapePt, holePt ) ) continue; + + holeIndex = h2; + indepHoles.splice( h, 1 ); + + tmpShape1 = shape.slice( 0, shapeIndex + 1 ); + tmpShape2 = shape.slice( shapeIndex ); + tmpHole1 = hole.slice( holeIndex ); + tmpHole2 = hole.slice( 0, holeIndex + 1 ); + + shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 ); + + minShapeIndex = shapeIndex; + + // Debug only, to show the selected cuts + // glob_CutLines.push( [ shapePt, holePt ] ); + + break; + + } + if ( holeIndex >= 0 ) break; // hole-vertex found + + failedCuts[ cutKey ] = true; // remember failure + + } + if ( holeIndex >= 0 ) break; // hole-vertex found + + } + + } + + return shape; /* shape with no holes */ + + } + + + var i, il, f, face, + key, index, + allPointsMap = {}; + + // To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first. + + var allpoints = contour.concat(); + + for ( var h = 0, hl = holes.length; h < hl; h ++ ) { + + Array.prototype.push.apply( allpoints, holes[ h ] ); + + } + + //console.log( "allpoints",allpoints, allpoints.length ); + + // prepare all points map + + for ( i = 0, il = allpoints.length; i < il; i ++ ) { + + key = allpoints[ i ].x + ":" + allpoints[ i ].y; + + if ( allPointsMap[ key ] !== undefined ) { + + console.warn( "THREE.ShapeUtils: Duplicate point", key, i ); + + } + + allPointsMap[ key ] = i; + + } + + // remove holes by cutting paths to holes and adding them to the shape + var shapeWithoutHoles = removeHoles( contour, holes ); + + var triangles = ShapeUtils.triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape + //console.log( "triangles",triangles, triangles.length ); + + // check all face vertices against all points map + + for ( i = 0, il = triangles.length; i < il; i ++ ) { + + face = triangles[ i ]; + + for ( f = 0; f < 3; f ++ ) { + + key = face[ f ].x + ":" + face[ f ].y; + + index = allPointsMap[ key ]; + + if ( index !== undefined ) { + + face[ f ] = index; + + } + + } + + } + + return triangles.concat(); + + }, + + isClockWise: function ( pts ) { + + return ShapeUtils.area( pts ) < 0; + + } + +}; + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * + * Creates extruded geometry from a path shape. + * + * parameters = { + * + * curveSegments: , // number of points on the curves + * steps: , // number of points for z-side extrusions / used for subdividing segments of extrude spline too + * amount: , // Depth to extrude the shape + * + * bevelEnabled: , // turn on bevel + * bevelThickness: , // how deep into the original shape bevel goes + * bevelSize: , // how far from shape outline is bevel + * bevelSegments: , // number of bevel layers + * + * extrudePath: // curve to extrude shape along + * frames: // containing arrays of tangents, normals, binormals + * + * uvGenerator: // object that provides UV generator functions + * + * } + **/ + +function ExtrudeGeometry( shapes, options ) { + + if ( typeof( shapes ) === "undefined" ) { + + shapes = []; + return; + + } + + Geometry.call( this ); + + this.type = 'ExtrudeGeometry'; + + shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; + + this.addShapeList( shapes, options ); + + this.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 ) ); + +} + +ExtrudeGeometry.prototype = Object.create( Geometry.prototype ); +ExtrudeGeometry.prototype.constructor = ExtrudeGeometry; + +ExtrudeGeometry.prototype.addShapeList = function ( shapes, options ) { + + var sl = shapes.length; + + for ( var s = 0; s < sl; s ++ ) { + + var shape = shapes[ s ]; + this.addShape( shape, options ); + + } + +}; + +ExtrudeGeometry.prototype.addShape = function ( shape, options ) { + + var amount = options.amount !== undefined ? options.amount : 100; + + var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10 + var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8 + var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; + + var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false + + var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; + + var steps = options.steps !== undefined ? options.steps : 1; + + var extrudePath = options.extrudePath; + var extrudePts, extrudeByPath = false; + + // Use default WorldUVGenerator if no UV generators are specified. + var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : ExtrudeGeometry.WorldUVGenerator; + + var splineTube, binormal, normal, position2; + if ( extrudePath ) { + + extrudePts = extrudePath.getSpacedPoints( steps ); + + extrudeByPath = true; + bevelEnabled = false; // bevels not supported for path extrusion + + // SETUP TNB variables + + // TODO1 - have a .isClosed in spline? + + splineTube = options.frames !== undefined ? options.frames : extrudePath.computeFrenetFrames( steps, false ); + + // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); + + binormal = new Vector3(); + normal = new Vector3(); + position2 = new Vector3(); + + } + + // Safeguards if bevels are not enabled + + if ( ! bevelEnabled ) { + + bevelSegments = 0; + bevelThickness = 0; + bevelSize = 0; + + } + + // Variables initialization + + var ahole, h, hl; // looping of holes + var scope = this; + + var shapesOffset = this.vertices.length; + + var shapePoints = shape.extractPoints( curveSegments ); + + var vertices = shapePoints.shape; + var holes = shapePoints.holes; + + var reverse = ! ShapeUtils.isClockWise( vertices ); + + if ( reverse ) { + + vertices = vertices.reverse(); + + // Maybe we should also check if holes are in the opposite direction, just to be safe ... + + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + + if ( ShapeUtils.isClockWise( ahole ) ) { + + holes[ h ] = ahole.reverse(); + + } + + } + + reverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)! + + } + + + var faces = ShapeUtils.triangulateShape( vertices, holes ); + + /* Vertices */ + + var contour = vertices; // vertices has all points but contour has only points of circumference + + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + + vertices = vertices.concat( ahole ); + + } + + + function scalePt2( pt, vec, size ) { + + if ( ! vec ) console.error( "THREE.ExtrudeGeometry: vec does not exist" ); + + return vec.clone().multiplyScalar( size ).add( pt ); + + } + + var b, bs, t, z, + vert, vlen = vertices.length, + face, flen = faces.length; + + + // Find directions for point movement + + + function getBevelVec( inPt, inPrev, inNext ) { + + // computes for inPt the corresponding point inPt' on a new contour + // shifted by 1 unit (length of normalized vector) to the left + // if we walk along contour clockwise, this new contour is outside the old one + // + // inPt' is the intersection of the two lines parallel to the two + // adjacent edges of inPt at a distance of 1 unit on the left side. + + var v_trans_x, v_trans_y, shrink_by = 1; // resulting translation vector for inPt + + // good reading for geometry algorithms (here: line-line intersection) + // http://geomalgorithms.com/a05-_intersect-1.html + + var v_prev_x = inPt.x - inPrev.x, v_prev_y = inPt.y - inPrev.y; + var v_next_x = inNext.x - inPt.x, v_next_y = inNext.y - inPt.y; + + var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); + + // check for collinear edges + var collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); + + if ( Math.abs( collinear0 ) > Number.EPSILON ) { + + // not collinear + + // length of vectors for normalizing + + var v_prev_len = Math.sqrt( v_prev_lensq ); + var v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); + + // shift adjacent points by unit vectors to the left + + var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); + var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); + + var ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); + var ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); + + // scaling factor for v_prev to intersection point + + var sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - + ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / + ( v_prev_x * v_next_y - v_prev_y * v_next_x ); + + // vector from inPt to intersection point + + v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); + v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); + + // Don't normalize!, otherwise sharp corners become ugly + // but prevent crazy spikes + var v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ); + if ( v_trans_lensq <= 2 ) { + + return new Vector2( v_trans_x, v_trans_y ); + + } else { + + shrink_by = Math.sqrt( v_trans_lensq / 2 ); + + } + + } else { + + // handle special case of collinear edges + + var direction_eq = false; // assumes: opposite + if ( v_prev_x > Number.EPSILON ) { + + if ( v_next_x > Number.EPSILON ) { + + direction_eq = true; + + } + + } else { + + if ( v_prev_x < - Number.EPSILON ) { + + if ( v_next_x < - Number.EPSILON ) { + + direction_eq = true; + + } + + } else { + + if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { + + direction_eq = true; + + } + + } + + } + + if ( direction_eq ) { + + // console.log("Warning: lines are a straight sequence"); + v_trans_x = - v_prev_y; + v_trans_y = v_prev_x; + shrink_by = Math.sqrt( v_prev_lensq ); + + } else { + + // console.log("Warning: lines are a straight spike"); + v_trans_x = v_prev_x; + v_trans_y = v_prev_y; + shrink_by = Math.sqrt( v_prev_lensq / 2 ); + + } + + } + + return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); + + } + + + var contourMovements = []; + + for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { + + if ( j === il ) j = 0; + if ( k === il ) k = 0; + + // (j)---(i)---(k) + // console.log('i,j,k', i, j , k) + + contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); + + } + + var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat(); + + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + + oneHoleMovements = []; + + for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { + + if ( j === il ) j = 0; + if ( k === il ) k = 0; + + // (j)---(i)---(k) + oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); + + } + + holesMovements.push( oneHoleMovements ); + verticesMovements = verticesMovements.concat( 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 * Math.cos( t * Math.PI / 2 ); + bs = bevelSize * Math.sin( t * Math.PI / 2 ); + + // contract shape + + for ( i = 0, il = contour.length; i < il; i ++ ) { + + vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); + + v( vert.x, vert.y, - z ); + + } + + // expand holes + + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; + + for ( i = 0, il = ahole.length; i < il; i ++ ) { + + vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); + + 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 ); + + } else { + + // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); + + normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x ); + binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y ); + + position2.copy( 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 <= steps; 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 / steps * s ); + + } else { + + // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); + + normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x ); + binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y ); + + position2.copy( 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 * Math.cos ( t * Math.PI / 2 ); + bs = bevelSize * Math.sin( t * Math.PI / 2 ); + + // contract shape + + for ( i = 0, il = contour.length; i < il; i ++ ) { + + vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); + v( vert.x, vert.y, amount + z ); + + } + + // expand holes + + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; + + for ( i = 0, il = ahole.length; i < il; i ++ ) { + + vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); + + if ( ! extrudeByPath ) { + + v( vert.x, vert.y, amount + z ); + + } else { + + v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); + + } + + } + + } + + } + + /* Faces */ + + // Top and bottom faces + + buildLidFaces(); + + // Sides faces + + buildSideFaces(); + + + ///// Internal functions + + function 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 ); + + } + + layer = steps + 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 ); + + } + + } else { + + // Bottom faces + + for ( i = 0; i < flen; i ++ ) { + + face = faces[ i ]; + f3( face[ 2 ], face[ 1 ], face[ 0 ] ); + + } + + // Top faces + + for ( i = 0; i < flen; i ++ ) { + + face = faces[ i ]; + f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); + + } + + } + + } + + // Create faces for the z-sides of the shape + + function buildSideFaces() { + + var layeroffset = 0; + sidewalls( contour, layeroffset ); + layeroffset += contour.length; + + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + sidewalls( ahole, layeroffset ); + + //, true + layeroffset += ahole.length; + + } + + } + + function sidewalls( contour, layeroffset ) { + + var 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 = steps + 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, j, k ); + + } + + } + + } + + + function v( x, y, z ) { + + scope.vertices.push( new Vector3( x, y, z ) ); + + } + + function f3( a, b, c ) { + + a += shapesOffset; + b += shapesOffset; + c += shapesOffset; + + scope.faces.push( new Face3( a, b, c, null, null, 0 ) ); + + var uvs = uvgen.generateTopUV( scope, a, b, c ); + + scope.faceVertexUvs[ 0 ].push( uvs ); + + } + + function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) { + + a += shapesOffset; + b += shapesOffset; + c += shapesOffset; + d += shapesOffset; + + scope.faces.push( new Face3( a, b, d, null, null, 1 ) ); + scope.faces.push( new Face3( b, c, d, null, null, 1 ) ); + + var uvs = uvgen.generateSideWallUV( scope, a, b, c, d ); + + scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] ); + scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] ); + + } + +}; + +ExtrudeGeometry.WorldUVGenerator = { + + generateTopUV: function ( geometry, indexA, indexB, indexC ) { + + var vertices = geometry.vertices; + + var a = vertices[ indexA ]; + var b = vertices[ indexB ]; + var c = vertices[ indexC ]; + + return [ + new Vector2( a.x, a.y ), + new Vector2( b.x, b.y ), + new Vector2( c.x, c.y ) + ]; + + }, + + generateSideWallUV: function ( geometry, indexA, indexB, indexC, indexD ) { + + var vertices = geometry.vertices; + + var a = vertices[ indexA ]; + var b = vertices[ indexB ]; + var c = vertices[ indexC ]; + var d = vertices[ indexD ]; + + if ( Math.abs( a.y - b.y ) < 0.01 ) { + + return [ + new Vector2( a.x, 1 - a.z ), + new Vector2( b.x, 1 - b.z ), + new Vector2( c.x, 1 - c.z ), + new Vector2( d.x, 1 - d.z ) + ]; + + } else { + + return [ + new Vector2( a.y, 1 - a.z ), + new Vector2( b.y, 1 - b.z ), + new Vector2( c.y, 1 - c.z ), + new Vector2( d.y, 1 - d.z ) + ]; + + } + + } +}; + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * @author alteredq / http://alteredqualia.com/ + * + * Text = 3D Text + * + * parameters = { + * font: , // font + * + * size: , // size of the text + * height: , // thickness to extrude text + * curveSegments: , // number of points on the curves + * + * bevelEnabled: , // turn on bevel + * bevelThickness: , // how deep into text bevel goes + * bevelSize: // how far from text outline is bevel + * } + */ + +function TextGeometry( text, parameters ) { + + parameters = parameters || {}; + + var font = parameters.font; + + if ( ( font && font.isFont ) === false ) { + + console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' ); + return new Geometry(); + + } + + var shapes = font.generateShapes( text, parameters.size, parameters.curveSegments ); + + // translate parameters to ExtrudeGeometry API + + parameters.amount = parameters.height !== undefined ? parameters.height : 50; + + // defaults + + if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10; + if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8; + if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false; + + ExtrudeGeometry.call( this, shapes, parameters ); + + this.type = 'TextGeometry'; + +} + +TextGeometry.prototype = Object.create( ExtrudeGeometry.prototype ); +TextGeometry.prototype.constructor = TextGeometry; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { + + Geometry.call( this ); + + this.type = 'SphereGeometry'; + + this.parameters = { + radius: radius, + widthSegments: widthSegments, + heightSegments: heightSegments, + phiStart: phiStart, + phiLength: phiLength, + thetaStart: thetaStart, + thetaLength: thetaLength + }; + + this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) ); + +} + +SphereGeometry.prototype = Object.create( Geometry.prototype ); +SphereGeometry.prototype.constructor = SphereGeometry; + +/** + * @author benaadams / https://twitter.com/ben_a_adams + * @author Mugen87 / https://github.com/Mugen87 + */ + +function SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { + + BufferGeometry.call( this ); + + this.type = 'SphereBufferGeometry'; + + this.parameters = { + radius: radius, + widthSegments: widthSegments, + heightSegments: heightSegments, + phiStart: phiStart, + phiLength: phiLength, + thetaStart: thetaStart, + thetaLength: thetaLength + }; + + radius = radius || 50; + + widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 ); + heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 ); + + phiStart = phiStart !== undefined ? phiStart : 0; + phiLength = phiLength !== undefined ? phiLength : Math.PI * 2; + + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; + + var thetaEnd = thetaStart + thetaLength; + + var ix, iy; + + var index = 0; + var grid = []; + + var vertex = new Vector3(); + var normal = new Vector3(); + + // buffers + + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; + + // generate vertices, normals and uvs + + for ( iy = 0; iy <= heightSegments; iy ++ ) { + + var verticesRow = []; + + var v = iy / heightSegments; + + for ( ix = 0; ix <= widthSegments; ix ++ ) { + + var u = ix / widthSegments; + + // vertex + + 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 ); + + vertices.push( vertex.x, vertex.y, vertex.z ); + + // normal + + normal.set( vertex.x, vertex.y, vertex.z ).normalize(); + normals.push( normal.x, normal.y, normal.z ); + + // uv + + uvs.push( u, 1 - v ); + + verticesRow.push( index ++ ); + + } + + grid.push( verticesRow ); + + } + + // indices + + for ( iy = 0; iy < heightSegments; iy ++ ) { + + for ( ix = 0; ix < widthSegments; ix ++ ) { + + var a = grid[ iy ][ ix + 1 ]; + var b = grid[ iy ][ ix ]; + var c = grid[ iy + 1 ][ ix ]; + var d = grid[ iy + 1 ][ ix + 1 ]; + + if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d ); + if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d ); + + } + + } + + // build geometry + + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + +} + +SphereBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +SphereBufferGeometry.prototype.constructor = SphereBufferGeometry; + +/** + * @author Kaleb Murphy + */ + +function RingGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { + + Geometry.call( this ); + + this.type = 'RingGeometry'; + + this.parameters = { + innerRadius: innerRadius, + outerRadius: outerRadius, + thetaSegments: thetaSegments, + phiSegments: phiSegments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; + + this.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) ); + +} + +RingGeometry.prototype = Object.create( Geometry.prototype ); +RingGeometry.prototype.constructor = RingGeometry; + +/** + * @author Mugen87 / https://github.com/Mugen87 + */ + +function RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { + + BufferGeometry.call( this ); + + this.type = 'RingBufferGeometry'; + + this.parameters = { + innerRadius: innerRadius, + outerRadius: outerRadius, + thetaSegments: thetaSegments, + phiSegments: phiSegments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; + + innerRadius = innerRadius || 20; + outerRadius = outerRadius || 50; + + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; + + thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8; + phiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 1; + + // buffers + + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; + + // some helper variables + + var segment; + var radius = innerRadius; + var radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); + var vertex = new Vector3(); + var uv = new Vector2(); + var j, i; + + // generate vertices, normals and uvs + + for ( j = 0; j <= phiSegments; j ++ ) { + + for ( i = 0; i <= thetaSegments; i ++ ) { + + // values are generate from the inside of the ring to the outside + + segment = thetaStart + i / thetaSegments * thetaLength; + + // vertex + + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); + + vertices.push( vertex.x, vertex.y, vertex.z ); + + // normal + + normals.push( 0, 0, 1 ); + + // uv + + uv.x = ( vertex.x / outerRadius + 1 ) / 2; + uv.y = ( vertex.y / outerRadius + 1 ) / 2; + + uvs.push( uv.x, uv.y ); + + } + + // increase the radius for next row of vertices + + radius += radiusStep; + + } + + // indices + + for ( j = 0; j < phiSegments; j ++ ) { + + var thetaSegmentLevel = j * ( thetaSegments + 1 ); + + for ( i = 0; i < thetaSegments; i ++ ) { + + segment = i + thetaSegmentLevel; + + var a = segment; + var b = segment + thetaSegments + 1; + var c = segment + thetaSegments + 2; + var d = segment + 1; + + // faces + + indices.push( a, b, d ); + indices.push( b, c, d ); + + } + + } + + // build geometry + + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + +} + +RingBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +RingBufferGeometry.prototype.constructor = RingBufferGeometry; + +/** + * @author astrodud / http://astrodud.isgreat.org/ + * @author zz85 / https://github.com/zz85 + * @author bhouston / http://clara.io + */ + +// points - to create a closed torus, one must use a set of points +// like so: [ a, b, c, d, a ], see first is the same as last. +// segments - the number of circumference segments to create +// phiStart - the starting radian +// phiLength - the radian (0 to 2PI) range of the lathed section +// 2PI is a closed lathe, less than 2PI is a portion. + +function LatheGeometry( points, segments, phiStart, phiLength ) { + + Geometry.call( this ); + + this.type = 'LatheGeometry'; + + this.parameters = { + points: points, + segments: segments, + phiStart: phiStart, + phiLength: phiLength + }; + + this.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) ); + this.mergeVertices(); + +} + +LatheGeometry.prototype = Object.create( Geometry.prototype ); +LatheGeometry.prototype.constructor = LatheGeometry; + +/** + * @author Mugen87 / https://github.com/Mugen87 + */ + +function LatheBufferGeometry( points, segments, phiStart, phiLength ) { + + BufferGeometry.call( this ); + + this.type = 'LatheBufferGeometry'; + + this.parameters = { + points: points, + segments: segments, + phiStart: phiStart, + phiLength: phiLength + }; + + segments = Math.floor( segments ) || 12; + phiStart = phiStart || 0; + phiLength = phiLength || Math.PI * 2; + + // clamp phiLength so it's in range of [ 0, 2PI ] + + phiLength = _Math.clamp( phiLength, 0, Math.PI * 2 ); + + + // buffers + + var indices = []; + var vertices = []; + var uvs = []; + + // helper variables + + var base; + var inverseSegments = 1.0 / segments; + var vertex = new Vector3(); + var uv = new Vector2(); + var i, j; + + // generate vertices and uvs + + for ( i = 0; i <= segments; i ++ ) { + + var phi = phiStart + i * inverseSegments * phiLength; + + var sin = Math.sin( phi ); + var cos = Math.cos( phi ); + + for ( j = 0; j <= ( points.length - 1 ); j ++ ) { + + // vertex + + vertex.x = points[ j ].x * sin; + vertex.y = points[ j ].y; + vertex.z = points[ j ].x * cos; + + vertices.push( vertex.x, vertex.y, vertex.z ); + + // uv + + uv.x = i / segments; + uv.y = j / ( points.length - 1 ); + + uvs.push( uv.x, uv.y ); + + + } + + } + + // indices + + for ( i = 0; i < segments; i ++ ) { + + for ( j = 0; j < ( points.length - 1 ); j ++ ) { + + base = j + i * points.length; + + var a = base; + var b = base + points.length; + var c = base + points.length + 1; + var d = base + 1; + + // faces + + indices.push( a, b, d ); + indices.push( b, c, d ); + + } + + } + + // build geometry + + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + + // generate normals + + this.computeVertexNormals(); + + // if the geometry is closed, we need to average the normals along the seam. + // because the corresponding vertices are identical (but still have different UVs). + + if ( phiLength === Math.PI * 2 ) { + + var normals = this.attributes.normal.array; + var n1 = new Vector3(); + var n2 = new Vector3(); + var n = new Vector3(); + + // this is the buffer offset for the last line of vertices + + base = segments * points.length * 3; + + for ( i = 0, j = 0; i < points.length; i ++, j += 3 ) { + + // select the normal of the vertex in the first line + + n1.x = normals[ j + 0 ]; + n1.y = normals[ j + 1 ]; + n1.z = normals[ j + 2 ]; + + // select the normal of the vertex in the last line + + n2.x = normals[ base + j + 0 ]; + n2.y = normals[ base + j + 1 ]; + n2.z = normals[ base + j + 2 ]; + + // average normals + + n.addVectors( n1, n2 ).normalize(); + + // assign the new values to both normals + + normals[ j + 0 ] = normals[ base + j + 0 ] = n.x; + normals[ j + 1 ] = normals[ base + j + 1 ] = n.y; + normals[ j + 2 ] = normals[ base + j + 2 ] = n.z; + + } + + } + +} + +LatheBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +LatheBufferGeometry.prototype.constructor = LatheBufferGeometry; + +/** + * @author jonobr1 / http://jonobr1.com + */ + +function ShapeGeometry( shapes, curveSegments ) { + + Geometry.call( this ); + + this.type = 'ShapeGeometry'; + + if ( typeof curveSegments === 'object' ) { + + console.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' ); + + curveSegments = curveSegments.curveSegments; + + } + + this.parameters = { + shapes: shapes, + curveSegments: curveSegments + }; + + this.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) ); + this.mergeVertices(); + +} + +ShapeGeometry.prototype = Object.create( Geometry.prototype ); +ShapeGeometry.prototype.constructor = ShapeGeometry; + +/** + * @author Mugen87 / https://github.com/Mugen87 + */ + +function ShapeBufferGeometry( shapes, curveSegments ) { + + BufferGeometry.call( this ); + + this.type = 'ShapeBufferGeometry'; + + this.parameters = { + shapes: shapes, + curveSegments: curveSegments + }; + + curveSegments = curveSegments || 12; + + // buffers + + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; + + // helper variables + + var groupStart = 0; + var groupCount = 0; + + // allow single and array values for "shapes" parameter + + if ( Array.isArray( shapes ) === false ) { + + addShape( shapes ); + + } else { + + for ( var i = 0; i < shapes.length; i ++ ) { + + addShape( shapes[ i ] ); + + this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support + + groupStart += groupCount; + groupCount = 0; + + } + + } + + // build geometry + + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + + + // helper functions + + function addShape( shape ) { + + var i, l, shapeHole; + + var indexOffset = vertices.length / 3; + var points = shape.extractPoints( curveSegments ); + + var shapeVertices = points.shape; + var shapeHoles = points.holes; + + // check direction of vertices + + if ( ShapeUtils.isClockWise( shapeVertices ) === false ) { + + shapeVertices = shapeVertices.reverse(); + + // also check if holes are in the opposite direction + + for ( i = 0, l = shapeHoles.length; i < l; i ++ ) { + + shapeHole = shapeHoles[ i ]; + + if ( ShapeUtils.isClockWise( shapeHole ) === true ) { + + shapeHoles[ i ] = shapeHole.reverse(); + + } + + } + + } + + var faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles ); + + // join vertices of inner and outer paths to a single array + + for ( i = 0, l = shapeHoles.length; i < l; i ++ ) { + + shapeHole = shapeHoles[ i ]; + shapeVertices = shapeVertices.concat( shapeHole ); + + } + + // vertices, normals, uvs + + for ( i = 0, l = shapeVertices.length; i < l; i ++ ) { + + var vertex = shapeVertices[ i ]; + + vertices.push( vertex.x, vertex.y, 0 ); + normals.push( 0, 0, 1 ); + uvs.push( vertex.x, vertex.y ); // world uvs + + } + + // incides + + for ( i = 0, l = faces.length; i < l; i ++ ) { + + var face = faces[ i ]; + + var a = face[ 0 ] + indexOffset; + var b = face[ 1 ] + indexOffset; + var c = face[ 2 ] + indexOffset; + + indices.push( a, b, c ); + groupCount += 3; + + } + + } + +} + +ShapeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +ShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry; + +/** + * @author WestLangley / http://github.com/WestLangley + * @author Mugen87 / https://github.com/Mugen87 + */ + +function EdgesGeometry( geometry, thresholdAngle ) { + + BufferGeometry.call( this ); + + this.type = 'EdgesGeometry'; + + this.parameters = { + thresholdAngle: thresholdAngle + }; + + thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1; + + // buffer + + var vertices = []; + + // helper variables + + var thresholdDot = Math.cos( _Math.DEG2RAD * thresholdAngle ); + var edge = [ 0, 0 ], edges = {}; + var key, keys = [ 'a', 'b', 'c' ]; + + // prepare source geometry + + var geometry2; + + if ( geometry.isBufferGeometry ) { + + geometry2 = new Geometry(); + geometry2.fromBufferGeometry( geometry ); + + } else { + + geometry2 = geometry.clone(); + + } + + geometry2.mergeVertices(); + geometry2.computeFaceNormals(); + + var sourceVertices = geometry2.vertices; + var faces = geometry2.faces; + + // now create a data structure where each entry represents an edge with its adjoining faces + + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + var face = faces[ i ]; + + for ( var j = 0; j < 3; j ++ ) { + + edge[ 0 ] = face[ keys[ j ] ]; + edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; + edge.sort( sortFunction ); + + key = edge.toString(); + + if ( edges[ key ] === undefined ) { + + edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ], face1: i, face2: undefined }; + + } else { + + edges[ key ].face2 = i; + + } + + } + + } + + // generate vertices + + for ( key in edges ) { + + var e = edges[ key ]; + + // an edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree. + + if ( e.face2 === undefined || faces[ e.face1 ].normal.dot( faces[ e.face2 ].normal ) <= thresholdDot ) { + + var vertex = sourceVertices[ e.index1 ]; + vertices.push( vertex.x, vertex.y, vertex.z ); + + vertex = sourceVertices[ e.index2 ]; + vertices.push( vertex.x, vertex.y, vertex.z ); + + } + + } + + // build geometry + + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + + // custom array sort function + + function sortFunction( a, b ) { + + return a - b; + + } + +} + +EdgesGeometry.prototype = Object.create( BufferGeometry.prototype ); +EdgesGeometry.prototype.constructor = EdgesGeometry; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { + + Geometry.call( this ); + + this.type = 'CylinderGeometry'; + + this.parameters = { + radiusTop: radiusTop, + radiusBottom: radiusBottom, + height: height, + radialSegments: radialSegments, + heightSegments: heightSegments, + openEnded: openEnded, + thetaStart: thetaStart, + thetaLength: thetaLength + }; + + this.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) ); + this.mergeVertices(); + +} + +CylinderGeometry.prototype = Object.create( Geometry.prototype ); +CylinderGeometry.prototype.constructor = CylinderGeometry; + +/** + * @author Mugen87 / https://github.com/Mugen87 + */ + +function CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { + + BufferGeometry.call( this ); + + this.type = 'CylinderBufferGeometry'; + + this.parameters = { + radiusTop: radiusTop, + radiusBottom: radiusBottom, + height: height, + radialSegments: radialSegments, + heightSegments: heightSegments, + openEnded: openEnded, + thetaStart: thetaStart, + thetaLength: thetaLength + }; + + var scope = this; + + radiusTop = radiusTop !== undefined ? radiusTop : 20; + radiusBottom = radiusBottom !== undefined ? radiusBottom : 20; + height = height !== undefined ? height : 100; + + radialSegments = Math.floor( radialSegments ) || 8; + heightSegments = Math.floor( heightSegments ) || 1; + + openEnded = openEnded !== undefined ? openEnded : false; + thetaStart = thetaStart !== undefined ? thetaStart : 0.0; + thetaLength = thetaLength !== undefined ? thetaLength : 2.0 * Math.PI; + + // buffers + + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; + + // helper variables + + var index = 0; + var indexOffset = 0; + var indexArray = []; + var halfHeight = height / 2; + var groupStart = 0; + + // generate geometry + + generateTorso(); + + if ( openEnded === false ) { + + if ( radiusTop > 0 ) generateCap( true ); + if ( radiusBottom > 0 ) generateCap( false ); + + } + + // build geometry + + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + + function generateTorso() { + + var x, y; + var normal = new Vector3(); + var vertex = new Vector3(); + + var groupCount = 0; + + // this will be used to calculate the normal + var slope = ( radiusBottom - radiusTop ) / height; + + // generate vertices, normals and uvs + + for ( y = 0; y <= heightSegments; y ++ ) { + + var indexRow = []; + + var v = y / heightSegments; + + // calculate the radius of the current row + + var radius = v * ( radiusBottom - radiusTop ) + radiusTop; + + for ( x = 0; x <= radialSegments; x ++ ) { + + var u = x / radialSegments; + + var theta = u * thetaLength + thetaStart; + + var sinTheta = Math.sin( theta ); + var cosTheta = Math.cos( theta ); + + // vertex + + vertex.x = radius * sinTheta; + vertex.y = - v * height + halfHeight; + vertex.z = radius * cosTheta; + vertices.push( vertex.x, vertex.y, vertex.z ); + + // normal + + normal.set( sinTheta, slope, cosTheta ).normalize(); + normals.push( normal.x, normal.y, normal.z ); + + // uv + + uvs.push( u, 1 - v ); + + // save index of vertex in respective row + + indexRow.push( index ++ ); + + } + + // now save vertices of the row in our index array + + indexArray.push( indexRow ); + + } + + // generate indices + + for ( x = 0; x < radialSegments; x ++ ) { + + for ( y = 0; y < heightSegments; y ++ ) { + + // we use the index array to access the correct indices + + var a = indexArray[ y ][ x ]; + var b = indexArray[ y + 1 ][ x ]; + var c = indexArray[ y + 1 ][ x + 1 ]; + var d = indexArray[ y ][ x + 1 ]; + + // faces + + indices.push( a, b, d ); + indices.push( b, c, d ); + + // update group counter + + groupCount += 6; + + } + + } + + // add a group to the geometry. this will ensure multi material support + + scope.addGroup( groupStart, groupCount, 0 ); + + // calculate new start value for groups + + groupStart += groupCount; + + } + + function generateCap( top ) { + + var x, centerIndexStart, centerIndexEnd; + + var uv = new Vector2(); + var vertex = new Vector3(); + + var groupCount = 0; + + var radius = ( top === true ) ? radiusTop : radiusBottom; + var sign = ( top === true ) ? 1 : - 1; + + // save the index of the first center vertex + centerIndexStart = index; + + // first we generate the center vertex data of the cap. + // because the geometry needs one set of uvs per face, + // we must generate a center vertex per face/segment + + for ( x = 1; x <= radialSegments; x ++ ) { + + // vertex + + vertices.push( 0, halfHeight * sign, 0 ); + + // normal + + normals.push( 0, sign, 0 ); + + // uv + + uvs.push( 0.5, 0.5 ); + + // increase index + + index ++; + + } + + // save the index of the last center vertex + + centerIndexEnd = index; + + // now we generate the surrounding vertices, normals and uvs + + for ( x = 0; x <= radialSegments; x ++ ) { + + var u = x / radialSegments; + var theta = u * thetaLength + thetaStart; + + var cosTheta = Math.cos( theta ); + var sinTheta = Math.sin( theta ); + + // vertex + + vertex.x = radius * sinTheta; + vertex.y = halfHeight * sign; + vertex.z = radius * cosTheta; + vertices.push( vertex.x, vertex.y, vertex.z ); + + // normal + + normals.push( 0, sign, 0 ); + + // uv + + uv.x = ( cosTheta * 0.5 ) + 0.5; + uv.y = ( sinTheta * 0.5 * sign ) + 0.5; + uvs.push( uv.x, uv.y ); + + // increase index + + index ++; + + } + + // generate indices + + for ( x = 0; x < radialSegments; x ++ ) { + + var c = centerIndexStart + x; + var i = centerIndexEnd + x; + + if ( top === true ) { + + // face top + + indices.push( i, i + 1, c ); + + } else { + + // face bottom + + indices.push( i + 1, i, c ); + + } + + groupCount += 3; + + } + + // add a group to the geometry. this will ensure multi material support + + scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 ); + + // calculate new start value for groups + + groupStart += groupCount; + + } + +} + +CylinderBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +CylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry; + +/** + * @author abelnation / http://github.com/abelnation + */ + +function ConeGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { + + CylinderGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); + + this.type = 'ConeGeometry'; + + this.parameters = { + radius: radius, + height: height, + radialSegments: radialSegments, + heightSegments: heightSegments, + openEnded: openEnded, + thetaStart: thetaStart, + thetaLength: thetaLength + }; + +} + +ConeGeometry.prototype = Object.create( CylinderGeometry.prototype ); +ConeGeometry.prototype.constructor = ConeGeometry; + +/** + * @author: abelnation / http://github.com/abelnation + */ + +function ConeBufferGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { + + CylinderBufferGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); + + this.type = 'ConeBufferGeometry'; + + this.parameters = { + radius: radius, + height: height, + radialSegments: radialSegments, + heightSegments: heightSegments, + openEnded: openEnded, + thetaStart: thetaStart, + thetaLength: thetaLength + }; + +} + +ConeBufferGeometry.prototype = Object.create( CylinderBufferGeometry.prototype ); +ConeBufferGeometry.prototype.constructor = ConeBufferGeometry; + +/** + * @author hughes + */ + +function CircleGeometry( radius, segments, thetaStart, thetaLength ) { + + Geometry.call( this ); + + this.type = 'CircleGeometry'; + + this.parameters = { + radius: radius, + segments: segments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; + + this.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) ); + +} + +CircleGeometry.prototype = Object.create( Geometry.prototype ); +CircleGeometry.prototype.constructor = CircleGeometry; + +/** + * @author benaadams / https://twitter.com/ben_a_adams + * @author Mugen87 / https://github.com/Mugen87 + */ + +function CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) { + + BufferGeometry.call( this ); + + this.type = 'CircleBufferGeometry'; + + this.parameters = { + radius: radius, + segments: segments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; + + radius = radius || 50; + segments = segments !== undefined ? Math.max( 3, segments ) : 8; + + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; + + // buffers + + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; + + // helper variables + + var i, s; + var vertex = new Vector3(); + var uv = new Vector2(); + + // center point + + vertices.push( 0, 0, 0 ); + normals.push( 0, 0, 1 ); + uvs.push( 0.5, 0.5 ); + + for ( s = 0, i = 3; s <= segments; s ++, i += 3 ) { + + var segment = thetaStart + s / segments * thetaLength; + + // vertex + + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); + + vertices.push( vertex.x, vertex.y, vertex.z ); + + // normal + + normals.push( 0, 0, 1 ); + + // uvs + + uv.x = ( vertices[ i ] / radius + 1 ) / 2; + uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2; + + uvs.push( uv.x, uv.y ); + + } + + // indices + + for ( i = 1; i <= segments; i ++ ) { + + indices.push( i, i + 1, 0 ); + + } + + // build geometry + + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + +} + +CircleBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +CircleBufferGeometry.prototype.constructor = CircleBufferGeometry; + + + +var Geometries = Object.freeze({ + WireframeGeometry: WireframeGeometry, + ParametricGeometry: ParametricGeometry, + ParametricBufferGeometry: ParametricBufferGeometry, + TetrahedronGeometry: TetrahedronGeometry, + TetrahedronBufferGeometry: TetrahedronBufferGeometry, + OctahedronGeometry: OctahedronGeometry, + OctahedronBufferGeometry: OctahedronBufferGeometry, + IcosahedronGeometry: IcosahedronGeometry, + IcosahedronBufferGeometry: IcosahedronBufferGeometry, + DodecahedronGeometry: DodecahedronGeometry, + DodecahedronBufferGeometry: DodecahedronBufferGeometry, + PolyhedronGeometry: PolyhedronGeometry, + PolyhedronBufferGeometry: PolyhedronBufferGeometry, + TubeGeometry: TubeGeometry, + TubeBufferGeometry: TubeBufferGeometry, + TorusKnotGeometry: TorusKnotGeometry, + TorusKnotBufferGeometry: TorusKnotBufferGeometry, + TorusGeometry: TorusGeometry, + TorusBufferGeometry: TorusBufferGeometry, + TextGeometry: TextGeometry, + SphereGeometry: SphereGeometry, + SphereBufferGeometry: SphereBufferGeometry, + RingGeometry: RingGeometry, + RingBufferGeometry: RingBufferGeometry, + PlaneGeometry: PlaneGeometry, + PlaneBufferGeometry: PlaneBufferGeometry, + LatheGeometry: LatheGeometry, + LatheBufferGeometry: LatheBufferGeometry, + ShapeGeometry: ShapeGeometry, + ShapeBufferGeometry: ShapeBufferGeometry, + ExtrudeGeometry: ExtrudeGeometry, + EdgesGeometry: EdgesGeometry, + ConeGeometry: ConeGeometry, + ConeBufferGeometry: ConeBufferGeometry, + CylinderGeometry: CylinderGeometry, + CylinderBufferGeometry: CylinderBufferGeometry, + CircleGeometry: CircleGeometry, + CircleBufferGeometry: CircleBufferGeometry, + BoxGeometry: BoxGeometry, + BoxBufferGeometry: BoxBufferGeometry +}); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function ShadowMaterial() { + + ShaderMaterial.call( this, { + uniforms: UniformsUtils.merge( [ + UniformsLib.lights, + { + opacity: { value: 1.0 } + } + ] ), + vertexShader: ShaderChunk[ 'shadow_vert' ], + fragmentShader: ShaderChunk[ 'shadow_frag' ] + } ); + + this.lights = true; + this.transparent = true; + + Object.defineProperties( this, { + opacity: { + enumerable: true, + get: function () { + return this.uniforms.opacity.value; + }, + set: function ( value ) { + this.uniforms.opacity.value = value; + } + } + } ); + +} + +ShadowMaterial.prototype = Object.create( ShaderMaterial.prototype ); +ShadowMaterial.prototype.constructor = ShadowMaterial; + +ShadowMaterial.prototype.isShadowMaterial = true; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function RawShaderMaterial( parameters ) { + + ShaderMaterial.call( this, parameters ); + + this.type = 'RawShaderMaterial'; + +} + +RawShaderMaterial.prototype = Object.create( ShaderMaterial.prototype ); +RawShaderMaterial.prototype.constructor = RawShaderMaterial; + +RawShaderMaterial.prototype.isRawShaderMaterial = true; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function MultiMaterial( materials ) { + + this.uuid = _Math.generateUUID(); + + this.type = 'MultiMaterial'; + + this.materials = Array.isArray( materials ) ? materials : []; + + this.visible = true; + +} + +MultiMaterial.prototype = { + + constructor: MultiMaterial, + + isMultiMaterial: true, + + toJSON: function ( meta ) { + + var output = { + metadata: { + version: 4.2, + type: 'material', + generator: 'MaterialExporter' + }, + uuid: this.uuid, + type: this.type, + materials: [] + }; + + var materials = this.materials; + + for ( var i = 0, l = materials.length; i < l; i ++ ) { + + var material = materials[ i ].toJSON( meta ); + delete material.metadata; + + output.materials.push( material ); + + } + + output.visible = this.visible; + + return output; + + }, + + clone: function () { + + var material = new this.constructor(); + + for ( var i = 0; i < this.materials.length; i ++ ) { + + material.materials.push( this.materials[ i ].clone() ); + + } + + material.visible = this.visible; + + return material; + + } + +}; + +/** + * @author WestLangley / http://github.com/WestLangley + * + * parameters = { + * color: , + * roughness: , + * metalness: , + * opacity: , + * + * map: new THREE.Texture( ), + * + * lightMap: new THREE.Texture( ), + * lightMapIntensity: + * + * aoMap: new THREE.Texture( ), + * aoMapIntensity: + * + * emissive: , + * emissiveIntensity: + * emissiveMap: new THREE.Texture( ), + * + * bumpMap: new THREE.Texture( ), + * bumpScale: , + * + * normalMap: new THREE.Texture( ), + * normalScale: , + * + * displacementMap: new THREE.Texture( ), + * displacementScale: , + * displacementBias: , + * + * roughnessMap: new THREE.Texture( ), + * + * metalnessMap: new THREE.Texture( ), + * + * alphaMap: new THREE.Texture( ), + * + * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ), + * envMapIntensity: + * + * refractionRatio: , + * + * wireframe: , + * wireframeLinewidth: , + * + * skinning: , + * morphTargets: , + * morphNormals: + * } + */ + +function MeshStandardMaterial( parameters ) { + + Material.call( this ); + + this.defines = { 'STANDARD': '' }; + + this.type = 'MeshStandardMaterial'; + + this.color = new Color( 0xffffff ); // diffuse + this.roughness = 0.5; + this.metalness = 0.5; + + this.map = null; + + this.lightMap = null; + this.lightMapIntensity = 1.0; + + this.aoMap = null; + this.aoMapIntensity = 1.0; + + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; + + this.bumpMap = null; + this.bumpScale = 1; + + this.normalMap = null; + this.normalScale = new Vector2( 1, 1 ); + + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; + + this.roughnessMap = null; + + this.metalnessMap = null; + + this.alphaMap = null; + + this.envMap = null; + this.envMapIntensity = 1.0; + + this.refractionRatio = 0.98; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; + + this.setValues( parameters ); + +} + +MeshStandardMaterial.prototype = Object.create( Material.prototype ); +MeshStandardMaterial.prototype.constructor = MeshStandardMaterial; + +MeshStandardMaterial.prototype.isMeshStandardMaterial = true; + +MeshStandardMaterial.prototype.copy = function ( source ) { + + Material.prototype.copy.call( this, source ); + + this.defines = { 'STANDARD': '' }; + + this.color.copy( source.color ); + this.roughness = source.roughness; + this.metalness = source.metalness; + + this.map = source.map; + + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; + + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; + + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; + + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; + + this.normalMap = source.normalMap; + this.normalScale.copy( source.normalScale ); + + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; + + this.roughnessMap = source.roughnessMap; + + this.metalnessMap = source.metalnessMap; + + this.alphaMap = source.alphaMap; + + this.envMap = source.envMap; + this.envMapIntensity = source.envMapIntensity; + + this.refractionRatio = source.refractionRatio; + + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; + + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; + + return this; + +}; + +/** + * @author WestLangley / http://github.com/WestLangley + * + * parameters = { + * reflectivity: + * } + */ + +function MeshPhysicalMaterial( parameters ) { + + MeshStandardMaterial.call( this ); + + this.defines = { 'PHYSICAL': '' }; + + this.type = 'MeshPhysicalMaterial'; + + this.reflectivity = 0.5; // maps to F0 = 0.04 + + this.clearCoat = 0.0; + this.clearCoatRoughness = 0.0; + + this.setValues( parameters ); + +} + +MeshPhysicalMaterial.prototype = Object.create( MeshStandardMaterial.prototype ); +MeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial; + +MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true; + +MeshPhysicalMaterial.prototype.copy = function ( source ) { + + MeshStandardMaterial.prototype.copy.call( this, source ); + + this.defines = { 'PHYSICAL': '' }; + + this.reflectivity = source.reflectivity; + + this.clearCoat = source.clearCoat; + this.clearCoatRoughness = source.clearCoatRoughness; + + return this; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * specular: , + * shininess: , + * opacity: , + * + * map: new THREE.Texture( ), + * + * lightMap: new THREE.Texture( ), + * lightMapIntensity: + * + * aoMap: new THREE.Texture( ), + * aoMapIntensity: + * + * emissive: , + * emissiveIntensity: + * emissiveMap: new THREE.Texture( ), + * + * bumpMap: new THREE.Texture( ), + * bumpScale: , + * + * normalMap: new THREE.Texture( ), + * normalScale: , + * + * displacementMap: new THREE.Texture( ), + * displacementScale: , + * displacementBias: , + * + * specularMap: new THREE.Texture( ), + * + * alphaMap: new THREE.Texture( ), + * + * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), + * combine: THREE.Multiply, + * reflectivity: , + * refractionRatio: , + * + * wireframe: , + * wireframeLinewidth: , + * + * skinning: , + * morphTargets: , + * morphNormals: + * } + */ + +function MeshPhongMaterial( parameters ) { + + Material.call( this ); + + this.type = 'MeshPhongMaterial'; + + this.color = new Color( 0xffffff ); // diffuse + this.specular = new Color( 0x111111 ); + this.shininess = 30; + + this.map = null; + + this.lightMap = null; + this.lightMapIntensity = 1.0; + + this.aoMap = null; + this.aoMapIntensity = 1.0; + + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; + + this.bumpMap = null; + this.bumpScale = 1; + + this.normalMap = null; + this.normalScale = new Vector2( 1, 1 ); + + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; + + this.specularMap = null; + + this.alphaMap = null; + + this.envMap = null; + this.combine = MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; + + this.setValues( parameters ); + +} + +MeshPhongMaterial.prototype = Object.create( Material.prototype ); +MeshPhongMaterial.prototype.constructor = MeshPhongMaterial; + +MeshPhongMaterial.prototype.isMeshPhongMaterial = true; + +MeshPhongMaterial.prototype.copy = function ( source ) { + + Material.prototype.copy.call( this, source ); + + this.color.copy( source.color ); + this.specular.copy( source.specular ); + this.shininess = source.shininess; + + this.map = source.map; + + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; + + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; + + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; + + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; + + this.normalMap = source.normalMap; + this.normalScale.copy( source.normalScale ); + + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; + + this.specularMap = source.specularMap; + + this.alphaMap = source.alphaMap; + + this.envMap = source.envMap; + this.combine = source.combine; + this.reflectivity = source.reflectivity; + this.refractionRatio = source.refractionRatio; + + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; + + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; + + return this; + +}; + +/** + * @author takahirox / http://github.com/takahirox + * + * parameters = { + * gradientMap: new THREE.Texture( ) + * } + */ + +function MeshToonMaterial( parameters ) { + + MeshPhongMaterial.call( this ); + + this.defines = { 'TOON': '' }; + + this.type = 'MeshToonMaterial'; + + this.gradientMap = null; + + this.setValues( parameters ); + +} + +MeshToonMaterial.prototype = Object.create( MeshPhongMaterial.prototype ); +MeshToonMaterial.prototype.constructor = MeshToonMaterial; + +MeshToonMaterial.prototype.isMeshToonMaterial = true; + +MeshToonMaterial.prototype.copy = function ( source ) { + + MeshPhongMaterial.prototype.copy.call( this, source ); + + this.gradientMap = source.gradientMap; + + return this; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley + * + * parameters = { + * opacity: , + * + * bumpMap: new THREE.Texture( ), + * bumpScale: , + * + * normalMap: new THREE.Texture( ), + * normalScale: , + * + * displacementMap: new THREE.Texture( ), + * displacementScale: , + * displacementBias: , + * + * wireframe: , + * wireframeLinewidth: + * + * skinning: , + * morphTargets: , + * morphNormals: + * } + */ + +function MeshNormalMaterial( parameters ) { + + Material.call( this, parameters ); + + this.type = 'MeshNormalMaterial'; + + this.bumpMap = null; + this.bumpScale = 1; + + this.normalMap = null; + this.normalScale = new Vector2( 1, 1 ); + + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; + + this.wireframe = false; + this.wireframeLinewidth = 1; + + this.fog = false; + this.lights = false; + + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; + + this.setValues( parameters ); + +} + +MeshNormalMaterial.prototype = Object.create( Material.prototype ); +MeshNormalMaterial.prototype.constructor = MeshNormalMaterial; + +MeshNormalMaterial.prototype.isMeshNormalMaterial = true; + +MeshNormalMaterial.prototype.copy = function ( source ) { + + Material.prototype.copy.call( this, source ); + + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; + + this.normalMap = source.normalMap; + this.normalScale.copy( source.normalScale ); + + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; + + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; + + return this; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * + * map: new THREE.Texture( ), + * + * lightMap: new THREE.Texture( ), + * lightMapIntensity: + * + * aoMap: new THREE.Texture( ), + * aoMapIntensity: + * + * emissive: , + * emissiveIntensity: + * emissiveMap: new THREE.Texture( ), + * + * specularMap: new THREE.Texture( ), + * + * alphaMap: new THREE.Texture( ), + * + * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), + * combine: THREE.Multiply, + * reflectivity: , + * refractionRatio: , + * + * wireframe: , + * wireframeLinewidth: , + * + * skinning: , + * morphTargets: , + * morphNormals: + * } + */ + +function MeshLambertMaterial( parameters ) { + + Material.call( this ); + + this.type = 'MeshLambertMaterial'; + + this.color = new Color( 0xffffff ); // diffuse + + this.map = null; + + this.lightMap = null; + this.lightMapIntensity = 1.0; + + this.aoMap = null; + this.aoMapIntensity = 1.0; + + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; + + this.specularMap = null; + + this.alphaMap = null; + + this.envMap = null; + this.combine = MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; + + this.setValues( parameters ); + +} + +MeshLambertMaterial.prototype = Object.create( Material.prototype ); +MeshLambertMaterial.prototype.constructor = MeshLambertMaterial; + +MeshLambertMaterial.prototype.isMeshLambertMaterial = true; + +MeshLambertMaterial.prototype.copy = function ( source ) { + + Material.prototype.copy.call( this, source ); + + this.color.copy( source.color ); + + this.map = source.map; + + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; + + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; + + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; + + this.specularMap = source.specularMap; + + this.alphaMap = source.alphaMap; + + this.envMap = source.envMap; + this.combine = source.combine; + this.reflectivity = source.reflectivity; + this.refractionRatio = source.refractionRatio; + + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; + + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; + + return this; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * + * linewidth: , + * + * scale: , + * dashSize: , + * gapSize: + * } + */ + +function LineDashedMaterial( parameters ) { + + Material.call( this ); + + this.type = 'LineDashedMaterial'; + + this.color = new Color( 0xffffff ); + + this.linewidth = 1; + + this.scale = 1; + this.dashSize = 3; + this.gapSize = 1; + + this.lights = false; + + this.setValues( parameters ); + +} + +LineDashedMaterial.prototype = Object.create( Material.prototype ); +LineDashedMaterial.prototype.constructor = LineDashedMaterial; + +LineDashedMaterial.prototype.isLineDashedMaterial = true; + +LineDashedMaterial.prototype.copy = function ( source ) { + + Material.prototype.copy.call( this, source ); + + this.color.copy( source.color ); + + this.linewidth = source.linewidth; + + this.scale = source.scale; + this.dashSize = source.dashSize; + this.gapSize = source.gapSize; + + return this; + +}; + + + +var Materials = Object.freeze({ + ShadowMaterial: ShadowMaterial, + SpriteMaterial: SpriteMaterial, + RawShaderMaterial: RawShaderMaterial, + ShaderMaterial: ShaderMaterial, + PointsMaterial: PointsMaterial, + MultiMaterial: MultiMaterial, + MeshPhysicalMaterial: MeshPhysicalMaterial, + MeshStandardMaterial: MeshStandardMaterial, + MeshPhongMaterial: MeshPhongMaterial, + MeshToonMaterial: MeshToonMaterial, + MeshNormalMaterial: MeshNormalMaterial, + MeshLambertMaterial: MeshLambertMaterial, + MeshDepthMaterial: MeshDepthMaterial, + MeshBasicMaterial: MeshBasicMaterial, + LineDashedMaterial: LineDashedMaterial, + LineBasicMaterial: LineBasicMaterial, + Material: Material +}); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +var Cache = { + + enabled: false, + + files: {}, + + add: function ( key, file ) { + + if ( this.enabled === false ) return; + + // console.log( 'THREE.Cache', 'Adding key:', key ); + + this.files[ key ] = file; + + }, + + get: function ( key ) { + + if ( this.enabled === false ) return; + + // console.log( 'THREE.Cache', 'Checking key:', key ); + + return this.files[ key ]; + + }, + + remove: function ( key ) { + + delete this.files[ key ]; + + }, + + clear: function () { + + this.files = {}; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function LoadingManager( onLoad, onProgress, onError ) { + + var scope = this; + + var isLoading = false, itemsLoaded = 0, itemsTotal = 0; + + this.onStart = undefined; + this.onLoad = onLoad; + this.onProgress = onProgress; + this.onError = onError; + + this.itemStart = function ( url ) { + + itemsTotal ++; + + if ( isLoading === false ) { + + if ( scope.onStart !== undefined ) { + + scope.onStart( url, itemsLoaded, itemsTotal ); + + } + + } + + isLoading = true; + + }; + + this.itemEnd = function ( url ) { + + itemsLoaded ++; + + if ( scope.onProgress !== undefined ) { + + scope.onProgress( url, itemsLoaded, itemsTotal ); + + } + + if ( itemsLoaded === itemsTotal ) { + + isLoading = false; + + if ( scope.onLoad !== undefined ) { + + scope.onLoad(); + + } + + } + + }; + + this.itemError = function ( url ) { + + if ( scope.onError !== undefined ) { + + scope.onError( url ); + + } + + }; + +} + +var DefaultLoadingManager = new LoadingManager(); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function FileLoader( manager ) { + + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + +} + +Object.assign( FileLoader.prototype, { + + load: function ( url, onLoad, onProgress, onError ) { + + if ( url === undefined ) url = ''; + + if ( this.path !== undefined ) url = this.path + url; + + var scope = this; + + var cached = Cache.get( url ); + + if ( cached !== undefined ) { + + scope.manager.itemStart( url ); + + setTimeout( function () { + + if ( onLoad ) onLoad( cached ); + + scope.manager.itemEnd( url ); + + }, 0 ); + + return cached; + + } + + // Check for data: URI + var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/; + var dataUriRegexResult = url.match( dataUriRegex ); + + // Safari can not handle Data URIs through XMLHttpRequest so process manually + if ( dataUriRegexResult ) { + + var mimeType = dataUriRegexResult[ 1 ]; + var isBase64 = !! dataUriRegexResult[ 2 ]; + var data = dataUriRegexResult[ 3 ]; + + data = window.decodeURIComponent( data ); + + if ( isBase64 ) data = window.atob( data ); + + try { + + var response; + var responseType = ( this.responseType || '' ).toLowerCase(); + + switch ( responseType ) { + + case 'arraybuffer': + case 'blob': + + response = new ArrayBuffer( data.length ); + + var view = new Uint8Array( response ); + + for ( var i = 0; i < data.length; i ++ ) { + + view[ i ] = data.charCodeAt( i ); + + } + + if ( responseType === 'blob' ) { + + response = new Blob( [ response ], { type: mimeType } ); + + } + + break; + + case 'document': + + var parser = new DOMParser(); + response = parser.parseFromString( data, mimeType ); + + break; + + case 'json': + + response = JSON.parse( data ); + + break; + + default: // 'text' or other + + response = data; + + break; + + } + + // Wait for next browser tick + window.setTimeout( function () { + + if ( onLoad ) onLoad( response ); + + scope.manager.itemEnd( url ); + + }, 0 ); + + } catch ( error ) { + + // Wait for next browser tick + window.setTimeout( function () { + + if ( onError ) onError( error ); + + scope.manager.itemError( url ); + + }, 0 ); + + } + + } else { + + var request = new XMLHttpRequest(); + request.open( 'GET', url, true ); + + request.addEventListener( 'load', function ( event ) { + + var response = event.target.response; + + Cache.add( url, response ); + + if ( this.status === 200 ) { + + if ( onLoad ) onLoad( response ); + + scope.manager.itemEnd( url ); + + } else if ( this.status === 0 ) { + + // Some browsers return HTTP Status 0 when using non-http protocol + // e.g. 'file://' or 'data://'. Handle as success. + + console.warn( 'THREE.FileLoader: HTTP Status 0 received.' ); + + if ( onLoad ) onLoad( response ); + + scope.manager.itemEnd( url ); + + } else { + + if ( onError ) onError( event ); + + scope.manager.itemError( url ); + + } + + }, false ); + + if ( onProgress !== undefined ) { + + request.addEventListener( 'progress', function ( event ) { + + onProgress( event ); + + }, false ); + + } + + request.addEventListener( 'error', function ( event ) { + + if ( onError ) onError( event ); + + scope.manager.itemError( url ); + + }, false ); + + if ( this.responseType !== undefined ) request.responseType = this.responseType; + if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials; + + if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' ); + + request.send( null ); + + } + + scope.manager.itemStart( url ); + + return request; + + }, + + setPath: function ( value ) { + + this.path = value; + return this; + + }, + + setResponseType: function ( value ) { + + this.responseType = value; + return this; + + }, + + setWithCredentials: function ( value ) { + + this.withCredentials = value; + return this; + + }, + + setMimeType: function ( value ) { + + this.mimeType = value; + return this; + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + * + * Abstract Base class to block based textures loader (dds, pvr, ...) + */ + +function CompressedTextureLoader( manager ) { + + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + + // override in sub classes + this._parser = null; + +} + +Object.assign( CompressedTextureLoader.prototype, { + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var images = []; + + var texture = new CompressedTexture(); + texture.image = images; + + var loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setResponseType( 'arraybuffer' ); + + function loadTexture( i ) { + + loader.load( url[ i ], function ( buffer ) { + + var texDatas = scope._parser( buffer, true ); + + images[ i ] = { + width: texDatas.width, + height: texDatas.height, + format: texDatas.format, + mipmaps: texDatas.mipmaps + }; + + loaded += 1; + + if ( loaded === 6 ) { + + if ( texDatas.mipmapCount === 1 ) + texture.minFilter = LinearFilter; + + texture.format = texDatas.format; + texture.needsUpdate = true; + + if ( onLoad ) onLoad( texture ); + + } + + }, onProgress, onError ); + + } + + if ( Array.isArray( url ) ) { + + var loaded = 0; + + for ( var i = 0, il = url.length; i < il; ++ i ) { + + loadTexture( i ); + + } + + } else { + + // compressed cubemap texture stored in a single DDS file + + loader.load( url, function ( buffer ) { + + var texDatas = scope._parser( buffer, true ); + + if ( texDatas.isCubemap ) { + + var faces = texDatas.mipmaps.length / texDatas.mipmapCount; + + for ( var f = 0; f < faces; f ++ ) { + + images[ f ] = { mipmaps : [] }; + + for ( var i = 0; i < texDatas.mipmapCount; i ++ ) { + + images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] ); + images[ f ].format = texDatas.format; + images[ f ].width = texDatas.width; + images[ f ].height = texDatas.height; + + } + + } + + } else { + + texture.image.width = texDatas.width; + texture.image.height = texDatas.height; + texture.mipmaps = texDatas.mipmaps; + + } + + if ( texDatas.mipmapCount === 1 ) { + + texture.minFilter = LinearFilter; + + } + + texture.format = texDatas.format; + texture.needsUpdate = true; + + if ( onLoad ) onLoad( texture ); + + }, onProgress, onError ); + + } + + return texture; + + }, + + setPath: function ( value ) { + + this.path = value; + return this; + + } + +} ); + +/** + * @author Nikos M. / https://github.com/foo123/ + * + * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) + */ + +function DataTextureLoader( manager ) { + + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + + // override in sub classes + this._parser = null; + +} + +Object.assign( DataTextureLoader.prototype, { + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var texture = new DataTexture(); + + var loader = new FileLoader( this.manager ); + loader.setResponseType( 'arraybuffer' ); + + loader.load( url, function ( buffer ) { + + var texData = scope._parser( buffer ); + + if ( ! texData ) return; + + if ( undefined !== texData.image ) { + + texture.image = texData.image; + + } else if ( undefined !== texData.data ) { + + texture.image.width = texData.width; + texture.image.height = texData.height; + texture.image.data = texData.data; + + } + + texture.wrapS = undefined !== texData.wrapS ? texData.wrapS : ClampToEdgeWrapping; + texture.wrapT = undefined !== texData.wrapT ? texData.wrapT : ClampToEdgeWrapping; + + texture.magFilter = undefined !== texData.magFilter ? texData.magFilter : LinearFilter; + texture.minFilter = undefined !== texData.minFilter ? texData.minFilter : LinearMipMapLinearFilter; + + texture.anisotropy = undefined !== texData.anisotropy ? texData.anisotropy : 1; + + if ( undefined !== texData.format ) { + + texture.format = texData.format; + + } + if ( undefined !== texData.type ) { + + texture.type = texData.type; + + } + + if ( undefined !== texData.mipmaps ) { + + texture.mipmaps = texData.mipmaps; + + } + + if ( 1 === texData.mipmapCount ) { + + texture.minFilter = LinearFilter; + + } + + texture.needsUpdate = true; + + if ( onLoad ) onLoad( texture, texData ); + + }, onProgress, onError ); + + + return texture; + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function ImageLoader( manager ) { + + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + +} + +Object.assign( ImageLoader.prototype, { + + load: function ( url, onLoad, onProgress, onError ) { + + if ( url === undefined ) url = ''; + + if ( this.path !== undefined ) url = this.path + url; + + var scope = this; + + var cached = Cache.get( url ); + + if ( cached !== undefined ) { + + scope.manager.itemStart( url ); + + setTimeout( function () { + + if ( onLoad ) onLoad( cached ); + + scope.manager.itemEnd( url ); + + }, 0 ); + + return cached; + + } + + var image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' ); + + image.addEventListener( 'load', function () { + + Cache.add( url, this ); + + if ( onLoad ) onLoad( this ); + + scope.manager.itemEnd( url ); + + }, false ); + + /* + image.addEventListener( 'progress', function ( event ) { + + if ( onProgress ) onProgress( event ); + + }, false ); + */ + + image.addEventListener( 'error', function ( event ) { + + if ( onError ) onError( event ); + + scope.manager.itemError( url ); + + }, false ); + + if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; + + scope.manager.itemStart( url ); + + image.src = url; + + return image; + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + return this; + + }, + + setPath: function ( value ) { + + this.path = value; + return this; + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function CubeTextureLoader( manager ) { + + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + +} + +Object.assign( CubeTextureLoader.prototype, { + + load: function ( urls, onLoad, onProgress, onError ) { + + var texture = new CubeTexture(); + + var loader = new ImageLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.setPath( this.path ); + + var loaded = 0; + + function loadTexture( i ) { + + loader.load( urls[ i ], function ( image ) { + + texture.images[ i ] = image; + + loaded ++; + + if ( loaded === 6 ) { + + texture.needsUpdate = true; + + if ( onLoad ) onLoad( texture ); + + } + + }, undefined, onError ); + + } + + for ( var i = 0; i < urls.length; ++ i ) { + + loadTexture( i ); + + } + + return texture; + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + return this; + + }, + + setPath: function ( value ) { + + this.path = value; + return this; + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function TextureLoader( manager ) { + + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + +} + +Object.assign( TextureLoader.prototype, { + + load: function ( url, onLoad, onProgress, onError ) { + + var texture = new Texture(); + + var loader = new ImageLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.setPath( this.path ); + loader.load( url, function ( image ) { + + // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB. + var isJPEG = url.search( /\.(jpg|jpeg)$/ ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0; + + texture.format = isJPEG ? RGBFormat : RGBAFormat; + texture.image = image; + texture.needsUpdate = true; + + if ( onLoad !== undefined ) { + + onLoad( texture ); + + } + + }, onProgress, onError ); + + return texture; + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + return this; + + }, + + setPath: function ( value ) { + + this.path = value; + return this; + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +function Light( color, intensity ) { + + Object3D.call( this ); + + this.type = 'Light'; + + this.color = new Color( color ); + this.intensity = intensity !== undefined ? intensity : 1; + + this.receiveShadow = undefined; + +} + +Light.prototype = Object.assign( Object.create( Object3D.prototype ), { + + constructor: Light, + + isLight: true, + + copy: function ( source ) { + + Object3D.prototype.copy.call( this, source ); + + this.color.copy( source.color ); + this.intensity = source.intensity; + + return this; + + }, + + toJSON: function ( meta ) { + + var data = Object3D.prototype.toJSON.call( this, meta ); + + data.object.color = this.color.getHex(); + data.object.intensity = this.intensity; + + if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); + + if ( this.distance !== undefined ) data.object.distance = this.distance; + if ( this.angle !== undefined ) data.object.angle = this.angle; + if ( this.decay !== undefined ) data.object.decay = this.decay; + if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra; + + if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON(); + + return data; + + } + +} ); + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +function HemisphereLight( skyColor, groundColor, intensity ) { + + Light.call( this, skyColor, intensity ); + + this.type = 'HemisphereLight'; + + this.castShadow = undefined; + + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); + + this.groundColor = new Color( groundColor ); + +} + +HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), { + + constructor: HemisphereLight, + + isHemisphereLight: true, + + copy: function ( source ) { + + Light.prototype.copy.call( this, source ); + + this.groundColor.copy( source.groundColor ); + + return this; + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function LightShadow( camera ) { + + this.camera = camera; + + this.bias = 0; + this.radius = 1; + + this.mapSize = new Vector2( 512, 512 ); + + this.map = null; + this.matrix = new Matrix4(); + +} + +Object.assign( LightShadow.prototype, { + + copy: function ( source ) { + + this.camera = source.camera.clone(); + + this.bias = source.bias; + this.radius = source.radius; + + this.mapSize.copy( source.mapSize ); + + return this; + + }, + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + toJSON: function () { + + var object = {}; + + if ( this.bias !== 0 ) object.bias = this.bias; + if ( this.radius !== 1 ) object.radius = this.radius; + if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); + + object.camera = this.camera.toJSON( false ).object; + delete object.camera.matrix; + + return object; + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function SpotLightShadow() { + + LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) ); + +} + +SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { + + constructor: SpotLightShadow, + + isSpotLightShadow: true, + + update: function ( light ) { + + var fov = _Math.RAD2DEG * 2 * light.angle; + var aspect = this.mapSize.width / this.mapSize.height; + var far = light.distance || 500; + + var camera = this.camera; + + if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { + + camera.fov = fov; + camera.aspect = aspect; + camera.far = far; + camera.updateProjectionMatrix(); + + } + + } + +} ); + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +function SpotLight( color, intensity, distance, angle, penumbra, decay ) { + + Light.call( this, color, intensity ); + + this.type = 'SpotLight'; + + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); + + this.target = new Object3D(); + + Object.defineProperty( this, 'power', { + get: function () { + // intensity = power per solid angle. + // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf + return this.intensity * Math.PI; + }, + set: function ( power ) { + // intensity = power per solid angle. + // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf + this.intensity = power / Math.PI; + } + } ); + + this.distance = ( distance !== undefined ) ? distance : 0; + this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; + this.penumbra = ( penumbra !== undefined ) ? penumbra : 0; + this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. + + this.shadow = new SpotLightShadow(); + +} + +SpotLight.prototype = Object.assign( Object.create( Light.prototype ), { + + constructor: SpotLight, + + isSpotLight: true, + + copy: function ( source ) { + + Light.prototype.copy.call( this, source ); + + this.distance = source.distance; + this.angle = source.angle; + this.penumbra = source.penumbra; + this.decay = source.decay; + + this.target = source.target.clone(); + + this.shadow = source.shadow.clone(); + + return this; + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + + +function PointLight( color, intensity, distance, decay ) { + + Light.call( this, color, intensity ); + + this.type = 'PointLight'; + + Object.defineProperty( this, 'power', { + get: function () { + // intensity = power per solid angle. + // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf + return this.intensity * 4 * Math.PI; + + }, + set: function ( power ) { + // intensity = power per solid angle. + // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf + this.intensity = power / ( 4 * Math.PI ); + } + } ); + + this.distance = ( distance !== undefined ) ? distance : 0; + this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. + + this.shadow = new LightShadow( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); + +} + +PointLight.prototype = Object.assign( Object.create( Light.prototype ), { + + constructor: PointLight, + + isPointLight: true, + + copy: function ( source ) { + + Light.prototype.copy.call( this, source ); + + this.distance = source.distance; + this.decay = source.decay; + + this.shadow = source.shadow.clone(); + + return this; + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function DirectionalLightShadow( ) { + + LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); + +} + +DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { + + constructor: DirectionalLightShadow + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +function DirectionalLight( color, intensity ) { + + Light.call( this, color, intensity ); + + this.type = 'DirectionalLight'; + + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); + + this.target = new Object3D(); + + this.shadow = new DirectionalLightShadow(); + +} + +DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), { + + constructor: DirectionalLight, + + isDirectionalLight: true, + + copy: function ( source ) { + + Light.prototype.copy.call( this, source ); + + this.target = source.target.clone(); + + this.shadow = source.shadow.clone(); + + return this; + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function AmbientLight( color, intensity ) { + + Light.call( this, color, intensity ); + + this.type = 'AmbientLight'; + + this.castShadow = undefined; + +} + +AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), { + + constructor: AmbientLight, + + isAmbientLight: true + +} ); + +/** + * @author tschw + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ + +var AnimationUtils = { + + // same as Array.prototype.slice, but also works on typed arrays + arraySlice: function( array, from, to ) { + + if ( AnimationUtils.isTypedArray( array ) ) { + + return new array.constructor( array.subarray( from, to ) ); + + } + + return array.slice( from, to ); + + }, + + // converts an array to a specific type + convertArray: function( array, type, forceClone ) { + + if ( ! array || // let 'undefined' and 'null' pass + ! forceClone && array.constructor === type ) return array; + + if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { + + return new type( array ); // create typed array + + } + + return Array.prototype.slice.call( array ); // create Array + + }, + + isTypedArray: function( object ) { + + return ArrayBuffer.isView( object ) && + ! ( object instanceof DataView ); + + }, + + // returns an array by which times and values can be sorted + getKeyframeOrder: function( times ) { + + function compareTime( i, j ) { + + return times[ i ] - times[ j ]; + + } + + var n = times.length; + var result = new Array( n ); + for ( var i = 0; i !== n; ++ i ) result[ i ] = i; + + result.sort( compareTime ); + + return result; + + }, + + // uses the array previously returned by 'getKeyframeOrder' to sort data + sortedArray: function( values, stride, order ) { + + var nValues = values.length; + var result = new values.constructor( nValues ); + + for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { + + var srcOffset = order[ i ] * stride; + + for ( var j = 0; j !== stride; ++ j ) { + + result[ dstOffset ++ ] = values[ srcOffset + j ]; + + } + + } + + return result; + + }, + + // function for parsing AOS keyframe formats + flattenJSON: function( jsonKeys, times, values, valuePropertyName ) { + + var i = 1, key = jsonKeys[ 0 ]; + + while ( key !== undefined && key[ valuePropertyName ] === undefined ) { + + key = jsonKeys[ i ++ ]; + + } + + if ( key === undefined ) return; // no data + + var value = key[ valuePropertyName ]; + if ( value === undefined ) return; // no data + + if ( Array.isArray( value ) ) { + + do { + + value = key[ valuePropertyName ]; + + if ( value !== undefined ) { + + times.push( key.time ); + values.push.apply( values, value ); // push all elements + + } + + key = jsonKeys[ i ++ ]; + + } while ( key !== undefined ); + + } else if ( value.toArray !== undefined ) { + // ...assume THREE.Math-ish + + do { + + value = key[ valuePropertyName ]; + + if ( value !== undefined ) { + + times.push( key.time ); + value.toArray( values, values.length ); + + } + + key = jsonKeys[ i ++ ]; + + } while ( key !== undefined ); + + } else { + // otherwise push as-is + + do { + + value = key[ valuePropertyName ]; + + if ( value !== undefined ) { + + times.push( key.time ); + values.push( value ); + + } + + key = jsonKeys[ i ++ ]; + + } while ( key !== undefined ); + + } + + } + +}; + +/** + * Abstract base class of interpolants over parametric samples. + * + * The parameter domain is one dimensional, typically the time or a path + * along a curve defined by the data. + * + * The sample values can have any dimensionality and derived classes may + * apply special interpretations to the data. + * + * This class provides the interval seek in a Template Method, deferring + * the actual interpolation to derived classes. + * + * Time complexity is O(1) for linear access crossing at most two points + * and O(log N) for random access, where N is the number of positions. + * + * References: + * + * http://www.oodesign.com/template-method-pattern.html + * + * @author tschw + */ + +function Interpolant( + parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + this.parameterPositions = parameterPositions; + this._cachedIndex = 0; + + this.resultBuffer = resultBuffer !== undefined ? + resultBuffer : new sampleValues.constructor( sampleSize ); + this.sampleValues = sampleValues; + this.valueSize = sampleSize; + +} + +Interpolant.prototype = { + + constructor: Interpolant, + + evaluate: function( t ) { + + var pp = this.parameterPositions, + i1 = this._cachedIndex, + + t1 = pp[ i1 ], + t0 = pp[ i1 - 1 ]; + + validate_interval: { + + seek: { + + var right; + + linear_scan: { +//- See http://jsperf.com/comparison-to-undefined/3 +//- slower code: +//- +//- if ( t >= t1 || t1 === undefined ) { + forward_scan: if ( ! ( t < t1 ) ) { + + for ( var giveUpAt = i1 + 2; ;) { + + if ( t1 === undefined ) { + + if ( t < t0 ) break forward_scan; + + // after end + + i1 = pp.length; + this._cachedIndex = i1; + return this.afterEnd_( i1 - 1, t, t0 ); + + } + + if ( i1 === giveUpAt ) break; // this loop + + t0 = t1; + t1 = pp[ ++ i1 ]; + + if ( t < t1 ) { + + // we have arrived at the sought interval + break seek; + + } + + } + + // prepare binary search on the right side of the index + right = pp.length; + break linear_scan; + + } + +//- slower code: +//- if ( t < t0 || t0 === undefined ) { + if ( ! ( t >= t0 ) ) { + + // looping? + + var t1global = pp[ 1 ]; + + if ( t < t1global ) { + + i1 = 2; // + 1, using the scan for the details + t0 = t1global; + + } + + // linear reverse scan + + for ( var giveUpAt = i1 - 2; ;) { + + if ( t0 === undefined ) { + + // before start + + this._cachedIndex = 0; + return this.beforeStart_( 0, t, t1 ); + + } + + if ( i1 === giveUpAt ) break; // this loop + + t1 = t0; + t0 = pp[ -- i1 - 1 ]; + + if ( t >= t0 ) { + + // we have arrived at the sought interval + break seek; + + } + + } + + // prepare binary search on the left side of the index + right = i1; + i1 = 0; + break linear_scan; + + } + + // the interval is valid + + break validate_interval; + + } // linear scan + + // binary search + + while ( i1 < right ) { + + var mid = ( i1 + right ) >>> 1; + + if ( t < pp[ mid ] ) { + + right = mid; + + } else { + + i1 = mid + 1; + + } + + } + + t1 = pp[ i1 ]; + t0 = pp[ i1 - 1 ]; + + // check boundary cases, again + + if ( t0 === undefined ) { + + this._cachedIndex = 0; + return this.beforeStart_( 0, t, t1 ); + + } + + if ( t1 === undefined ) { + + i1 = pp.length; + this._cachedIndex = i1; + return this.afterEnd_( i1 - 1, t0, t ); + + } + + } // seek + + this._cachedIndex = i1; + + this.intervalChanged_( i1, t0, t1 ); + + } // validate_interval + + return this.interpolate_( i1, t0, t, t1 ); + + }, + + settings: null, // optional, subclass-specific settings structure + // Note: The indirection allows central control of many interpolants. + + // --- Protected interface + + DefaultSettings_: {}, + + getSettings_: function() { + + return this.settings || this.DefaultSettings_; + + }, + + copySampleValue_: function( index ) { + + // copies a sample value to the result buffer + + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + offset = index * stride; + + for ( var i = 0; i !== stride; ++ i ) { + + result[ i ] = values[ offset + i ]; + + } + + return result; + + }, + + // Template methods for derived classes: + + interpolate_: function( i1, t0, t, t1 ) { + + throw new Error( "call to abstract method" ); + // implementations shall return this.resultBuffer + + }, + + intervalChanged_: function( i1, t0, t1 ) { + + // empty + + } + +}; + +Object.assign( Interpolant.prototype, { + + beforeStart_: //( 0, t, t0 ), returns this.resultBuffer + Interpolant.prototype.copySampleValue_, + + afterEnd_: //( N-1, tN-1, t ), returns this.resultBuffer + Interpolant.prototype.copySampleValue_ + +} ); + +/** + * Fast and simple cubic spline interpolant. + * + * It was derived from a Hermitian construction setting the first derivative + * at each sample position to the linear slope between neighboring positions + * over their parameter interval. + * + * @author tschw + */ + +function CubicInterpolant( + parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + Interpolant.call( + this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + + this._weightPrev = -0; + this._offsetPrev = -0; + this._weightNext = -0; + this._offsetNext = -0; + +} + +CubicInterpolant.prototype = + Object.assign( Object.create( Interpolant.prototype ), { + + constructor: CubicInterpolant, + + DefaultSettings_: { + + endingStart: ZeroCurvatureEnding, + endingEnd: ZeroCurvatureEnding + + }, + + intervalChanged_: function( i1, t0, t1 ) { + + var pp = this.parameterPositions, + iPrev = i1 - 2, + iNext = i1 + 1, + + tPrev = pp[ iPrev ], + tNext = pp[ iNext ]; + + if ( tPrev === undefined ) { + + switch ( this.getSettings_().endingStart ) { + + case ZeroSlopeEnding: + + // f'(t0) = 0 + iPrev = i1; + tPrev = 2 * t0 - t1; + + break; + + case WrapAroundEnding: + + // use the other end of the curve + iPrev = pp.length - 2; + tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; + + break; + + default: // ZeroCurvatureEnding + + // f''(t0) = 0 a.k.a. Natural Spline + iPrev = i1; + tPrev = t1; + + } + + } + + if ( tNext === undefined ) { + + switch ( this.getSettings_().endingEnd ) { + + case ZeroSlopeEnding: + + // f'(tN) = 0 + iNext = i1; + tNext = 2 * t1 - t0; + + break; + + case WrapAroundEnding: + + // use the other end of the curve + iNext = 1; + tNext = t1 + pp[ 1 ] - pp[ 0 ]; + + break; + + default: // ZeroCurvatureEnding + + // f''(tN) = 0, a.k.a. Natural Spline + iNext = i1 - 1; + tNext = t0; + + } + + } + + var halfDt = ( t1 - t0 ) * 0.5, + stride = this.valueSize; + + this._weightPrev = halfDt / ( t0 - tPrev ); + this._weightNext = halfDt / ( tNext - t1 ); + this._offsetPrev = iPrev * stride; + this._offsetNext = iNext * stride; + + }, + + interpolate_: function( i1, t0, t, t1 ) { + + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + + o1 = i1 * stride, o0 = o1 - stride, + oP = this._offsetPrev, oN = this._offsetNext, + wP = this._weightPrev, wN = this._weightNext, + + p = ( t - t0 ) / ( t1 - t0 ), + pp = p * p, + ppp = pp * p; + + // evaluate polynomials + + var sP = - wP * ppp + 2 * wP * pp - wP * p; + var s0 = ( 1 + wP ) * ppp + (-1.5 - 2 * wP ) * pp + ( -0.5 + wP ) * p + 1; + var s1 = (-1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; + var sN = wN * ppp - wN * pp; + + // combine data linearly + + for ( var i = 0; i !== stride; ++ i ) { + + result[ i ] = + sP * values[ oP + i ] + + s0 * values[ o0 + i ] + + s1 * values[ o1 + i ] + + sN * values[ oN + i ]; + + } + + return result; + + } + +} ); + +/** + * @author tschw + */ + +function LinearInterpolant( + parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + Interpolant.call( + this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + +} + +LinearInterpolant.prototype = + Object.assign( Object.create( Interpolant.prototype ), { + + constructor: LinearInterpolant, + + interpolate_: function( i1, t0, t, t1 ) { + + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + + offset1 = i1 * stride, + offset0 = offset1 - stride, + + weight1 = ( t - t0 ) / ( t1 - t0 ), + weight0 = 1 - weight1; + + for ( var i = 0; i !== stride; ++ i ) { + + result[ i ] = + values[ offset0 + i ] * weight0 + + values[ offset1 + i ] * weight1; + + } + + return result; + + } + +} ); + +/** + * + * Interpolant that evaluates to the sample value at the position preceeding + * the parameter. + * + * @author tschw + */ + +function DiscreteInterpolant( + parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + Interpolant.call( + this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + +} + +DiscreteInterpolant.prototype = + Object.assign( Object.create( Interpolant.prototype ), { + + constructor: DiscreteInterpolant, + + interpolate_: function( i1, t0, t, t1 ) { + + return this.copySampleValue_( i1 - 1 ); + + } + +} ); + +var KeyframeTrackPrototype; + +KeyframeTrackPrototype = { + + TimeBufferType: Float32Array, + ValueBufferType: Float32Array, + + DefaultInterpolation: InterpolateLinear, + + InterpolantFactoryMethodDiscrete: function ( result ) { + + return new DiscreteInterpolant( + this.times, this.values, this.getValueSize(), result ); + + }, + + InterpolantFactoryMethodLinear: function ( result ) { + + return new LinearInterpolant( + this.times, this.values, this.getValueSize(), result ); + + }, + + InterpolantFactoryMethodSmooth: function ( result ) { + + return new CubicInterpolant( + this.times, this.values, this.getValueSize(), result ); + + }, + + setInterpolation: function ( interpolation ) { + + var factoryMethod; + + switch ( interpolation ) { + + case InterpolateDiscrete: + + factoryMethod = this.InterpolantFactoryMethodDiscrete; + + break; + + case InterpolateLinear: + + factoryMethod = this.InterpolantFactoryMethodLinear; + + break; + + case InterpolateSmooth: + + factoryMethod = this.InterpolantFactoryMethodSmooth; + + break; + + } + + if ( factoryMethod === undefined ) { + + var message = "unsupported interpolation for " + + this.ValueTypeName + " keyframe track named " + this.name; + + if ( this.createInterpolant === undefined ) { + + // fall back to default, unless the default itself is messed up + if ( interpolation !== this.DefaultInterpolation ) { + + this.setInterpolation( this.DefaultInterpolation ); + + } else { + + throw new Error( message ); // fatal, in this case + + } + + } + + console.warn( message ); + return; + + } + + this.createInterpolant = factoryMethod; + + }, + + getInterpolation: function () { + + switch ( this.createInterpolant ) { + + case this.InterpolantFactoryMethodDiscrete: + + return InterpolateDiscrete; + + case this.InterpolantFactoryMethodLinear: + + return InterpolateLinear; + + case this.InterpolantFactoryMethodSmooth: + + return InterpolateSmooth; + + } + + }, + + getValueSize: function () { + + return this.values.length / this.times.length; + + }, + + // move all keyframes either forwards or backwards in time + shift: function ( timeOffset ) { + + if ( timeOffset !== 0.0 ) { + + var times = this.times; + + for ( var i = 0, n = times.length; i !== n; ++ i ) { + + times[ i ] += timeOffset; + + } + + } + + return this; + + }, + + // scale all keyframe times by a factor (useful for frame <-> seconds conversions) + scale: function ( timeScale ) { + + if ( timeScale !== 1.0 ) { + + var times = this.times; + + for ( var i = 0, n = times.length; i !== n; ++ i ) { + + times[ i ] *= timeScale; + + } + + } + + return this; + + }, + + // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. + // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values + trim: function ( startTime, endTime ) { + + var times = this.times, + nKeys = times.length, + from = 0, + to = nKeys - 1; + + while ( from !== nKeys && times[ from ] < startTime ) ++ from; + while ( to !== - 1 && times[ to ] > endTime ) -- to; + + ++ to; // inclusive -> exclusive bound + + if ( from !== 0 || to !== nKeys ) { + + // empty tracks are forbidden, so keep at least one keyframe + if ( from >= to ) to = Math.max( to, 1 ), from = to - 1; + + var stride = this.getValueSize(); + this.times = AnimationUtils.arraySlice( times, from, to ); + this.values = AnimationUtils. + arraySlice( this.values, from * stride, to * stride ); + + } + + return this; + + }, + + // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable + validate: function () { + + var valid = true; + + var valueSize = this.getValueSize(); + if ( valueSize - Math.floor( valueSize ) !== 0 ) { + + console.error( "invalid value size in track", this ); + valid = false; + + } + + var times = this.times, + values = this.values, + + nKeys = times.length; + + if ( nKeys === 0 ) { + + console.error( "track is empty", this ); + valid = false; + + } + + var prevTime = null; + + for ( var i = 0; i !== nKeys; i ++ ) { + + var currTime = times[ i ]; + + if ( typeof currTime === 'number' && isNaN( currTime ) ) { + + console.error( "time is not a valid number", this, i, currTime ); + valid = false; + break; + + } + + if ( prevTime !== null && prevTime > currTime ) { + + console.error( "out of order keys", this, i, currTime, prevTime ); + valid = false; + break; + + } + + prevTime = currTime; + + } + + if ( values !== undefined ) { + + if ( AnimationUtils.isTypedArray( values ) ) { + + for ( var i = 0, n = values.length; i !== n; ++ i ) { + + var value = values[ i ]; + + if ( isNaN( value ) ) { + + console.error( "value is not a valid number", this, i, value ); + valid = false; + break; + + } + + } + + } + + } + + return valid; + + }, + + // removes equivalent sequential keys as common in morph target sequences + // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) + optimize: function () { + + var times = this.times, + values = this.values, + stride = this.getValueSize(), + + smoothInterpolation = this.getInterpolation() === InterpolateSmooth, + + writeIndex = 1, + lastIndex = times.length - 1; + + for ( var i = 1; i < lastIndex; ++ i ) { + + var keep = false; + + var time = times[ i ]; + var timeNext = times[ i + 1 ]; + + // remove adjacent keyframes scheduled at the same time + + if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) { + + if ( ! smoothInterpolation ) { + + // remove unnecessary keyframes same as their neighbors + + var offset = i * stride, + offsetP = offset - stride, + offsetN = offset + stride; + + for ( var j = 0; j !== stride; ++ j ) { + + var value = values[ offset + j ]; + + if ( value !== values[ offsetP + j ] || + value !== values[ offsetN + j ] ) { + + keep = true; + break; + + } + + } + + } else keep = true; + + } + + // in-place compaction + + if ( keep ) { + + if ( i !== writeIndex ) { + + times[ writeIndex ] = times[ i ]; + + var readOffset = i * stride, + writeOffset = writeIndex * stride; + + for ( var j = 0; j !== stride; ++ j ) + + values[ writeOffset + j ] = values[ readOffset + j ]; + + } + + ++ writeIndex; + + } + + } + + // flush last keyframe (compaction looks ahead) + + if ( lastIndex > 0 ) { + + times[ writeIndex ] = times[ lastIndex ]; + + for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) + + values[ writeOffset + j ] = values[ readOffset + j ]; + + ++ writeIndex; + + } + + if ( writeIndex !== times.length ) { + + this.times = AnimationUtils.arraySlice( times, 0, writeIndex ); + this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride ); + + } + + return this; + + } + +}; + +function KeyframeTrackConstructor( name, times, values, interpolation ) { + + if( name === undefined ) throw new Error( "track name is undefined" ); + + if( times === undefined || times.length === 0 ) { + + throw new Error( "no keyframes in track named " + name ); + + } + + this.name = name; + + this.times = AnimationUtils.convertArray( times, this.TimeBufferType ); + this.values = AnimationUtils.convertArray( values, this.ValueBufferType ); + + this.setInterpolation( interpolation || this.DefaultInterpolation ); + + this.validate(); + this.optimize(); + +} + +/** + * + * A Track of vectored keyframe values. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ + +function VectorKeyframeTrack( name, times, values, interpolation ) { + + KeyframeTrackConstructor.call( this, name, times, values, interpolation ); + +} + +VectorKeyframeTrack.prototype = + Object.assign( Object.create( KeyframeTrackPrototype ), { + + constructor: VectorKeyframeTrack, + + ValueTypeName: 'vector' + + // ValueBufferType is inherited + + // DefaultInterpolation is inherited + +} ); + +/** + * Spherical linear unit quaternion interpolant. + * + * @author tschw + */ + +function QuaternionLinearInterpolant( + parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + Interpolant.call( + this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + +} + +QuaternionLinearInterpolant.prototype = + Object.assign( Object.create( Interpolant.prototype ), { + + constructor: QuaternionLinearInterpolant, + + interpolate_: function( i1, t0, t, t1 ) { + + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + + offset = i1 * stride, + + alpha = ( t - t0 ) / ( t1 - t0 ); + + for ( var end = offset + stride; offset !== end; offset += 4 ) { + + Quaternion.slerpFlat( result, 0, + values, offset - stride, values, offset, alpha ); + + } + + return result; + + } + +} ); + +/** + * + * A Track of quaternion keyframe values. + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ + +function QuaternionKeyframeTrack( name, times, values, interpolation ) { + + KeyframeTrackConstructor.call( this, name, times, values, interpolation ); + +} + +QuaternionKeyframeTrack.prototype = + Object.assign( Object.create( KeyframeTrackPrototype ), { + + constructor: QuaternionKeyframeTrack, + + ValueTypeName: 'quaternion', + + // ValueBufferType is inherited + + DefaultInterpolation: InterpolateLinear, + + InterpolantFactoryMethodLinear: function( result ) { + + return new QuaternionLinearInterpolant( + this.times, this.values, this.getValueSize(), result ); + + }, + + InterpolantFactoryMethodSmooth: undefined // not yet implemented + +} ); + +/** + * + * A Track of numeric keyframe values. + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ + +function NumberKeyframeTrack( name, times, values, interpolation ) { + + KeyframeTrackConstructor.call( this, name, times, values, interpolation ); + +} + +NumberKeyframeTrack.prototype = + Object.assign( Object.create( KeyframeTrackPrototype ), { + + constructor: NumberKeyframeTrack, + + ValueTypeName: 'number' + + // ValueBufferType is inherited + + // DefaultInterpolation is inherited + +} ); + +/** + * + * A Track that interpolates Strings + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ + +function StringKeyframeTrack( name, times, values, interpolation ) { + + KeyframeTrackConstructor.call( this, name, times, values, interpolation ); + +} + +StringKeyframeTrack.prototype = + Object.assign( Object.create( KeyframeTrackPrototype ), { + + constructor: StringKeyframeTrack, + + ValueTypeName: 'string', + ValueBufferType: Array, + + DefaultInterpolation: InterpolateDiscrete, + + InterpolantFactoryMethodLinear: undefined, + + InterpolantFactoryMethodSmooth: undefined + +} ); + +/** + * + * A Track of Boolean keyframe values. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ + +function BooleanKeyframeTrack( name, times, values ) { + + KeyframeTrackConstructor.call( this, name, times, values ); + +} + +BooleanKeyframeTrack.prototype = + Object.assign( Object.create( KeyframeTrackPrototype ), { + + constructor: BooleanKeyframeTrack, + + ValueTypeName: 'bool', + ValueBufferType: Array, + + DefaultInterpolation: InterpolateDiscrete, + + InterpolantFactoryMethodLinear: undefined, + InterpolantFactoryMethodSmooth: undefined + + // Note: Actually this track could have a optimized / compressed + // representation of a single value and a custom interpolant that + // computes "firstValue ^ isOdd( index )". + +} ); + +/** + * + * A Track of keyframe values that represent color. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ + +function ColorKeyframeTrack( name, times, values, interpolation ) { + + KeyframeTrackConstructor.call( this, name, times, values, interpolation ); + +} + +ColorKeyframeTrack.prototype = + Object.assign( Object.create( KeyframeTrackPrototype ), { + + constructor: ColorKeyframeTrack, + + ValueTypeName: 'color' + + // ValueBufferType is inherited + + // DefaultInterpolation is inherited + + + // Note: Very basic implementation and nothing special yet. + // However, this is the place for color space parameterization. + +} ); + +/** + * + * A timed sequence of keyframes for a specific property. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ + +function KeyframeTrack( name, times, values, interpolation ) { + + KeyframeTrackConstructor.apply( this, arguments ); + +} + +KeyframeTrack.prototype = KeyframeTrackPrototype; +KeyframeTrackPrototype.constructor = KeyframeTrack; + +// Static methods: + +Object.assign( KeyframeTrack, { + + // Serialization (in static context, because of constructor invocation + // and automatic invocation of .toJSON): + + parse: function( json ) { + + if( json.type === undefined ) { + + throw new Error( "track type undefined, can not parse" ); + + } + + var trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type ); + + if ( json.times === undefined ) { + + var times = [], values = []; + + AnimationUtils.flattenJSON( json.keys, times, values, 'value' ); + + json.times = times; + json.values = values; + + } + + // derived classes can define a static parse method + if ( trackType.parse !== undefined ) { + + return trackType.parse( json ); + + } else { + + // by default, we asssume a constructor compatible with the base + return new trackType( + json.name, json.times, json.values, json.interpolation ); + + } + + }, + + toJSON: function( track ) { + + var trackType = track.constructor; + + var json; + + // derived classes can define a static toJSON method + if ( trackType.toJSON !== undefined ) { + + json = trackType.toJSON( track ); + + } else { + + // by default, we assume the data can be serialized as-is + json = { + + 'name': track.name, + 'times': AnimationUtils.convertArray( track.times, Array ), + 'values': AnimationUtils.convertArray( track.values, Array ) + + }; + + var interpolation = track.getInterpolation(); + + if ( interpolation !== track.DefaultInterpolation ) { + + json.interpolation = interpolation; + + } + + } + + json.type = track.ValueTypeName; // mandatory + + return json; + + }, + + _getTrackTypeForValueTypeName: function( typeName ) { + + switch( typeName.toLowerCase() ) { + + case "scalar": + case "double": + case "float": + case "number": + case "integer": + + return NumberKeyframeTrack; + + case "vector": + case "vector2": + case "vector3": + case "vector4": + + return VectorKeyframeTrack; + + case "color": + + return ColorKeyframeTrack; + + case "quaternion": + + return QuaternionKeyframeTrack; + + case "bool": + case "boolean": + + return BooleanKeyframeTrack; + + case "string": + + return StringKeyframeTrack; + + } + + throw new Error( "Unsupported typeName: " + typeName ); + + } + +} ); + +/** + * + * Reusable set of Tracks that represent an animation. + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ + +function AnimationClip( name, duration, tracks ) { + + this.name = name; + this.tracks = tracks; + this.duration = ( duration !== undefined ) ? duration : -1; + + this.uuid = _Math.generateUUID(); + + // this means it should figure out its duration by scanning the tracks + if ( this.duration < 0 ) { + + this.resetDuration(); + + } + + this.optimize(); + +} + +AnimationClip.prototype = { + + constructor: AnimationClip, + + resetDuration: function() { + + var tracks = this.tracks, + duration = 0; + + for ( var i = 0, n = tracks.length; i !== n; ++ i ) { + + var track = this.tracks[ i ]; + + duration = Math.max( duration, track.times[ track.times.length - 1 ] ); + + } + + this.duration = duration; + + }, + + trim: function() { + + for ( var i = 0; i < this.tracks.length; i ++ ) { + + this.tracks[ i ].trim( 0, this.duration ); + + } + + return this; + + }, + + optimize: function() { + + for ( var i = 0; i < this.tracks.length; i ++ ) { + + this.tracks[ i ].optimize(); + + } + + return this; + + } + +}; + +// Static methods: + +Object.assign( AnimationClip, { + + parse: function( json ) { + + var tracks = [], + jsonTracks = json.tracks, + frameTime = 1.0 / ( json.fps || 1.0 ); + + for ( var i = 0, n = jsonTracks.length; i !== n; ++ i ) { + + tracks.push( KeyframeTrack.parse( jsonTracks[ i ] ).scale( frameTime ) ); + + } + + return new AnimationClip( json.name, json.duration, tracks ); + + }, + + + toJSON: function( clip ) { + + var tracks = [], + clipTracks = clip.tracks; + + var json = { + + 'name': clip.name, + 'duration': clip.duration, + 'tracks': tracks + + }; + + for ( var i = 0, n = clipTracks.length; i !== n; ++ i ) { + + tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); + + } + + return json; + + }, + + + CreateFromMorphTargetSequence: function( name, morphTargetSequence, fps, noLoop ) { + + var numMorphTargets = morphTargetSequence.length; + var tracks = []; + + for ( var i = 0; i < numMorphTargets; i ++ ) { + + var times = []; + var values = []; + + times.push( + ( i + numMorphTargets - 1 ) % numMorphTargets, + i, + ( i + 1 ) % numMorphTargets ); + + values.push( 0, 1, 0 ); + + var order = AnimationUtils.getKeyframeOrder( times ); + times = AnimationUtils.sortedArray( times, 1, order ); + values = AnimationUtils.sortedArray( values, 1, order ); + + // if there is a key at the first frame, duplicate it as the + // last frame as well for perfect loop. + if ( ! noLoop && times[ 0 ] === 0 ) { + + times.push( numMorphTargets ); + values.push( values[ 0 ] ); + + } + + tracks.push( + new NumberKeyframeTrack( + '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', + times, values + ).scale( 1.0 / fps ) ); + } + + return new AnimationClip( name, -1, tracks ); + + }, + + findByName: function( objectOrClipArray, name ) { + + var clipArray = objectOrClipArray; + + if ( ! Array.isArray( objectOrClipArray ) ) { + + var o = objectOrClipArray; + clipArray = o.geometry && o.geometry.animations || o.animations; + + } + + for ( var i = 0; i < clipArray.length; i ++ ) { + + if ( clipArray[ i ].name === name ) { + + return clipArray[ i ]; + + } + } + + return null; + + }, + + CreateClipsFromMorphTargetSequences: function( morphTargets, fps, noLoop ) { + + var animationToMorphTargets = {}; + + // tested with https://regex101.com/ on trick sequences + // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 + var pattern = /^([\w-]*?)([\d]+)$/; + + // sort morph target names into animation groups based + // patterns like Walk_001, Walk_002, Run_001, Run_002 + for ( var i = 0, il = morphTargets.length; i < il; i ++ ) { + + var morphTarget = morphTargets[ i ]; + var parts = morphTarget.name.match( pattern ); + + if ( parts && parts.length > 1 ) { + + var name = parts[ 1 ]; + + var animationMorphTargets = animationToMorphTargets[ name ]; + if ( ! animationMorphTargets ) { + + animationToMorphTargets[ name ] = animationMorphTargets = []; + + } + + animationMorphTargets.push( morphTarget ); + + } + + } + + var clips = []; + + for ( var name in animationToMorphTargets ) { + + clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); + + } + + return clips; + + }, + + // parse the animation.hierarchy format + parseAnimation: function( animation, bones ) { + + if ( ! animation ) { + + console.error( " no animation in JSONLoader data" ); + return null; + + } + + var addNonemptyTrack = function( + trackType, trackName, animationKeys, propertyName, destTracks ) { + + // only return track if there are actually keys. + if ( animationKeys.length !== 0 ) { + + var times = []; + var values = []; + + AnimationUtils.flattenJSON( + animationKeys, times, values, propertyName ); + + // empty keys are filtered out, so check again + if ( times.length !== 0 ) { + + destTracks.push( new trackType( trackName, times, values ) ); + + } + + } + + }; + + var tracks = []; + + var clipName = animation.name || 'default'; + // automatic length determination in AnimationClip. + var duration = animation.length || -1; + var fps = animation.fps || 30; + + var hierarchyTracks = animation.hierarchy || []; + + for ( var h = 0; h < hierarchyTracks.length; h ++ ) { + + var animationKeys = hierarchyTracks[ h ].keys; + + // skip empty tracks + if ( ! animationKeys || animationKeys.length === 0 ) continue; + + // process morph targets in a way exactly compatible + // with AnimationHandler.init( animation ) + if ( animationKeys[0].morphTargets ) { + + // figure out all morph targets used in this track + var morphTargetNames = {}; + for ( var k = 0; k < animationKeys.length; k ++ ) { + + if ( animationKeys[k].morphTargets ) { + + for ( var m = 0; m < animationKeys[k].morphTargets.length; m ++ ) { + + morphTargetNames[ animationKeys[k].morphTargets[m] ] = -1; + } + + } + + } + + // create a track for each morph target with all zero + // morphTargetInfluences except for the keys in which + // the morphTarget is named. + for ( var morphTargetName in morphTargetNames ) { + + var times = []; + var values = []; + + for ( var m = 0; m !== animationKeys[k].morphTargets.length; ++ m ) { + + var animationKey = animationKeys[k]; + + times.push( animationKey.time ); + values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); + + } + + tracks.push( new NumberKeyframeTrack('.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); + + } + + duration = morphTargetNames.length * ( fps || 1.0 ); + + } else { + // ...assume skeletal animation + + var boneName = '.bones[' + bones[ h ].name + ']'; + + addNonemptyTrack( + VectorKeyframeTrack, boneName + '.position', + animationKeys, 'pos', tracks ); + + addNonemptyTrack( + QuaternionKeyframeTrack, boneName + '.quaternion', + animationKeys, 'rot', tracks ); + + addNonemptyTrack( + VectorKeyframeTrack, boneName + '.scale', + animationKeys, 'scl', tracks ); + + } + + } + + if ( tracks.length === 0 ) { + + return null; + + } + + var clip = new AnimationClip( clipName, duration, tracks ); + + return clip; + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function MaterialLoader( manager ) { + + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + this.textures = {}; + +} + +Object.assign( MaterialLoader.prototype, { + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var loader = new FileLoader( scope.manager ); + loader.load( url, function ( text ) { + + onLoad( scope.parse( JSON.parse( text ) ) ); + + }, onProgress, onError ); + + }, + + setTextures: function ( value ) { + + this.textures = value; + + }, + + parse: function ( json ) { + + var textures = this.textures; + + function getTexture( name ) { + + if ( textures[ name ] === undefined ) { + + console.warn( 'THREE.MaterialLoader: Undefined texture', name ); + + } + + return textures[ name ]; + + } + + var material = new Materials[ json.type ](); + + if ( json.uuid !== undefined ) material.uuid = json.uuid; + if ( json.name !== undefined ) material.name = json.name; + if ( json.color !== undefined ) material.color.setHex( json.color ); + if ( json.roughness !== undefined ) material.roughness = json.roughness; + if ( json.metalness !== undefined ) material.metalness = json.metalness; + if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive ); + if ( json.specular !== undefined ) material.specular.setHex( json.specular ); + if ( json.shininess !== undefined ) material.shininess = json.shininess; + if ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat; + if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness; + if ( json.uniforms !== undefined ) material.uniforms = json.uniforms; + if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; + if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; + if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors; + if ( json.fog !== undefined ) material.fog = json.fog; + if ( json.shading !== undefined ) material.shading = json.shading; + if ( json.blending !== undefined ) material.blending = json.blending; + if ( json.side !== undefined ) material.side = json.side; + if ( json.opacity !== undefined ) material.opacity = json.opacity; + if ( json.transparent !== undefined ) material.transparent = json.transparent; + if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; + if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; + if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; + if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; + if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; + if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; + if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; + if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; + if ( json.skinning !== undefined ) material.skinning = json.skinning; + if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets; + + // for PointsMaterial + + if ( json.size !== undefined ) material.size = json.size; + if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; + + // maps + + if ( json.map !== undefined ) material.map = getTexture( json.map ); + + if ( json.alphaMap !== undefined ) { + + material.alphaMap = getTexture( json.alphaMap ); + material.transparent = true; + + } + + if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); + if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; + + if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); + if ( json.normalScale !== undefined ) { + + var normalScale = json.normalScale; + + if ( Array.isArray( normalScale ) === false ) { + + // Blender exporter used to export a scalar. See #7459 + + normalScale = [ normalScale, normalScale ]; + + } + + material.normalScale = new Vector2().fromArray( normalScale ); + + } + + if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap ); + if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; + if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; + + if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap ); + if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap ); + + if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap ); + if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity; + + if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); + + if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); + + if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; + + if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); + if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; + + if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap ); + if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; + + if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); + + // MultiMaterial + + if ( json.materials !== undefined ) { + + for ( var i = 0, l = json.materials.length; i < l; i ++ ) { + + material.materials.push( this.parse( json.materials[ i ] ) ); + + } + + } + + return material; + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function BufferGeometryLoader( manager ) { + + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + +} + +Object.assign( BufferGeometryLoader.prototype, { + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var loader = new FileLoader( scope.manager ); + loader.load( url, function ( text ) { + + onLoad( scope.parse( JSON.parse( text ) ) ); + + }, onProgress, onError ); + + }, + + parse: function ( json ) { + + var geometry = new BufferGeometry(); + + var index = json.data.index; + + var TYPED_ARRAYS = { + 'Int8Array': Int8Array, + 'Uint8Array': Uint8Array, + 'Uint8ClampedArray': Uint8ClampedArray, + 'Int16Array': Int16Array, + 'Uint16Array': Uint16Array, + 'Int32Array': Int32Array, + 'Uint32Array': Uint32Array, + 'Float32Array': Float32Array, + 'Float64Array': Float64Array + }; + + if ( index !== undefined ) { + + var typedArray = new TYPED_ARRAYS[ index.type ]( index.array ); + geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); + + } + + var attributes = json.data.attributes; + + for ( var key in attributes ) { + + var attribute = attributes[ key ]; + var typedArray = new TYPED_ARRAYS[ attribute.type ]( attribute.array ); + + geometry.addAttribute( key, new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ) ); + + } + + var groups = json.data.groups || json.data.drawcalls || json.data.offsets; + + if ( groups !== undefined ) { + + for ( var i = 0, n = groups.length; i !== n; ++ i ) { + + var group = groups[ i ]; + + geometry.addGroup( group.start, group.count, group.materialIndex ); + + } + + } + + var boundingSphere = json.data.boundingSphere; + + if ( boundingSphere !== undefined ) { + + var center = new Vector3(); + + if ( boundingSphere.center !== undefined ) { + + center.fromArray( boundingSphere.center ); + + } + + geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); + + } + + return geometry; + + } + +} ); + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +function Loader() { + + this.onLoadStart = function () {}; + this.onLoadProgress = function () {}; + this.onLoadComplete = function () {}; + +} + +Loader.prototype = { + + constructor: Loader, + + crossOrigin: undefined, + + extractUrlBase: function ( url ) { + + var parts = url.split( '/' ); + + if ( parts.length === 1 ) return './'; + + parts.pop(); + + return parts.join( '/' ) + '/'; + + }, + + initMaterials: function ( materials, texturePath, crossOrigin ) { + + var array = []; + + for ( var i = 0; i < materials.length; ++ i ) { + + array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin ); + + } + + return array; + + }, + + createMaterial: ( function () { + + var BlendingMode = { + NoBlending: NoBlending, + NormalBlending: NormalBlending, + AdditiveBlending: AdditiveBlending, + SubtractiveBlending: SubtractiveBlending, + MultiplyBlending: MultiplyBlending, + CustomBlending: CustomBlending + }; + + var color, textureLoader, materialLoader; + + return function createMaterial( m, texturePath, crossOrigin ) { + + if ( color === undefined ) color = new Color(); + if ( textureLoader === undefined ) textureLoader = new TextureLoader(); + if ( materialLoader === undefined ) materialLoader = new MaterialLoader(); + + // convert from old material format + + var textures = {}; + + function loadTexture( path, repeat, offset, wrap, anisotropy ) { + + var fullPath = texturePath + path; + var loader = Loader.Handlers.get( fullPath ); + + var texture; + + if ( loader !== null ) { + + texture = loader.load( fullPath ); + + } else { + + textureLoader.setCrossOrigin( crossOrigin ); + texture = textureLoader.load( fullPath ); + + } + + if ( repeat !== undefined ) { + + texture.repeat.fromArray( repeat ); + + if ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping; + if ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping; + + } + + if ( offset !== undefined ) { + + texture.offset.fromArray( offset ); + + } + + if ( wrap !== undefined ) { + + if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping; + if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping; + + if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping; + if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping; + + } + + if ( anisotropy !== undefined ) { + + texture.anisotropy = anisotropy; + + } + + var uuid = _Math.generateUUID(); + + textures[ uuid ] = texture; + + return uuid; + + } + + // + + var json = { + uuid: _Math.generateUUID(), + type: 'MeshLambertMaterial' + }; + + for ( var name in m ) { + + var value = m[ name ]; + + switch ( name ) { + + case 'DbgColor': + case 'DbgIndex': + case 'opticalDensity': + case 'illumination': + break; + case 'DbgName': + json.name = value; + break; + case 'blending': + json.blending = BlendingMode[ value ]; + break; + case 'colorAmbient': + case 'mapAmbient': + console.warn( 'THREE.Loader.createMaterial:', name, 'is no longer supported.' ); + break; + case 'colorDiffuse': + json.color = color.fromArray( value ).getHex(); + break; + case 'colorSpecular': + json.specular = color.fromArray( value ).getHex(); + break; + case 'colorEmissive': + json.emissive = color.fromArray( value ).getHex(); + break; + case 'specularCoef': + json.shininess = value; + break; + case 'shading': + if ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial'; + if ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial'; + if ( value.toLowerCase() === 'standard' ) json.type = 'MeshStandardMaterial'; + break; + case 'mapDiffuse': + json.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); + break; + case 'mapDiffuseRepeat': + case 'mapDiffuseOffset': + case 'mapDiffuseWrap': + case 'mapDiffuseAnisotropy': + break; + case 'mapEmissive': + json.emissiveMap = loadTexture( value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy ); + break; + case 'mapEmissiveRepeat': + case 'mapEmissiveOffset': + case 'mapEmissiveWrap': + case 'mapEmissiveAnisotropy': + break; + case 'mapLight': + json.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); + break; + case 'mapLightRepeat': + case 'mapLightOffset': + case 'mapLightWrap': + case 'mapLightAnisotropy': + break; + case 'mapAO': + json.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy ); + break; + case 'mapAORepeat': + case 'mapAOOffset': + case 'mapAOWrap': + case 'mapAOAnisotropy': + break; + case 'mapBump': + json.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); + break; + case 'mapBumpScale': + json.bumpScale = value; + break; + case 'mapBumpRepeat': + case 'mapBumpOffset': + case 'mapBumpWrap': + case 'mapBumpAnisotropy': + break; + case 'mapNormal': + json.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); + break; + case 'mapNormalFactor': + json.normalScale = [ value, value ]; + break; + case 'mapNormalRepeat': + case 'mapNormalOffset': + case 'mapNormalWrap': + case 'mapNormalAnisotropy': + break; + case 'mapSpecular': + json.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); + break; + case 'mapSpecularRepeat': + case 'mapSpecularOffset': + case 'mapSpecularWrap': + case 'mapSpecularAnisotropy': + break; + case 'mapMetalness': + json.metalnessMap = loadTexture( value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy ); + break; + case 'mapMetalnessRepeat': + case 'mapMetalnessOffset': + case 'mapMetalnessWrap': + case 'mapMetalnessAnisotropy': + break; + case 'mapRoughness': + json.roughnessMap = loadTexture( value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy ); + break; + case 'mapRoughnessRepeat': + case 'mapRoughnessOffset': + case 'mapRoughnessWrap': + case 'mapRoughnessAnisotropy': + break; + case 'mapAlpha': + json.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy ); + break; + case 'mapAlphaRepeat': + case 'mapAlphaOffset': + case 'mapAlphaWrap': + case 'mapAlphaAnisotropy': + break; + case 'flipSided': + json.side = BackSide; + break; + case 'doubleSided': + json.side = DoubleSide; + break; + case 'transparency': + console.warn( 'THREE.Loader.createMaterial: transparency has been renamed to opacity' ); + json.opacity = value; + break; + case 'depthTest': + case 'depthWrite': + case 'colorWrite': + case 'opacity': + case 'reflectivity': + case 'transparent': + case 'visible': + case 'wireframe': + json[ name ] = value; + break; + case 'vertexColors': + if ( value === true ) json.vertexColors = VertexColors; + if ( value === 'face' ) json.vertexColors = FaceColors; + break; + default: + console.error( 'THREE.Loader.createMaterial: Unsupported', name, value ); + break; + + } + + } + + if ( json.type === 'MeshBasicMaterial' ) delete json.emissive; + if ( json.type !== 'MeshPhongMaterial' ) delete json.specular; + + if ( json.opacity < 1 ) json.transparent = true; + + materialLoader.setTextures( textures ); + + return materialLoader.parse( json ); + + }; + + } )() + +}; + +Loader.Handlers = { + + handlers: [], + + add: function ( regex, loader ) { + + this.handlers.push( regex, loader ); + + }, + + get: function ( file ) { + + var handlers = this.handlers; + + for ( var i = 0, l = handlers.length; i < l; i += 2 ) { + + var regex = handlers[ i ]; + var loader = handlers[ i + 1 ]; + + if ( regex.test( file ) ) { + + return loader; + + } + + } + + return null; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +function JSONLoader( manager ) { + + if ( typeof manager === 'boolean' ) { + + console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' ); + manager = undefined; + + } + + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + + this.withCredentials = false; + +} + +Object.assign( JSONLoader.prototype, { + + load: function( url, onLoad, onProgress, onError ) { + + var scope = this; + + var texturePath = this.texturePath && ( typeof this.texturePath === "string" ) ? this.texturePath : Loader.prototype.extractUrlBase( url ); + + var loader = new FileLoader( this.manager ); + loader.setWithCredentials( this.withCredentials ); + loader.load( url, function ( text ) { + + var json = JSON.parse( text ); + var metadata = json.metadata; + + if ( metadata !== undefined ) { + + var type = metadata.type; + + if ( type !== undefined ) { + + if ( type.toLowerCase() === 'object' ) { + + console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' ); + return; + + } + + if ( type.toLowerCase() === 'scene' ) { + + console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.SceneLoader instead.' ); + return; + + } + + } + + } + + var object = scope.parse( json, texturePath ); + onLoad( object.geometry, object.materials ); + + }, onProgress, onError ); + + }, + + setTexturePath: function ( value ) { + + this.texturePath = value; + + }, + + parse: function ( json, texturePath ) { + + var geometry = new Geometry(), + scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; + + parseModel( scale ); + + parseSkin(); + parseMorphing( scale ); + parseAnimations(); + + geometry.computeFaceNormals(); + geometry.computeBoundingSphere(); + + function parseModel( scale ) { + + function isBitSet( value, position ) { + + return value & ( 1 << position ); + + } + + var i, j, fi, + + offset, zLength, + + colorIndex, normalIndex, uvIndex, materialIndex, + + type, + isQuad, + hasMaterial, + hasFaceVertexUv, + hasFaceNormal, hasFaceVertexNormal, + hasFaceColor, hasFaceVertexColor, + + vertex, face, faceA, faceB, hex, normal, + + uvLayer, uv, u, v, + + faces = json.faces, + vertices = json.vertices, + normals = json.normals, + colors = json.colors, + + nUvLayers = 0; + + if ( json.uvs !== undefined ) { + + // disregard empty arrays + + for ( i = 0; i < json.uvs.length; i ++ ) { + + if ( json.uvs[ i ].length ) nUvLayers ++; + + } + + for ( i = 0; i < nUvLayers; i ++ ) { + + geometry.faceVertexUvs[ i ] = []; + + } + + } + + offset = 0; + zLength = vertices.length; + + while ( offset < zLength ) { + + vertex = new Vector3(); + + vertex.x = vertices[ offset ++ ] * scale; + vertex.y = vertices[ offset ++ ] * scale; + vertex.z = vertices[ offset ++ ] * scale; + + geometry.vertices.push( vertex ); + + } + + offset = 0; + zLength = faces.length; + + while ( offset < zLength ) { + + type = faces[ offset ++ ]; + + + isQuad = isBitSet( type, 0 ); + hasMaterial = isBitSet( type, 1 ); + hasFaceVertexUv = isBitSet( type, 3 ); + hasFaceNormal = isBitSet( type, 4 ); + hasFaceVertexNormal = isBitSet( type, 5 ); + hasFaceColor = isBitSet( type, 6 ); + hasFaceVertexColor = isBitSet( type, 7 ); + + // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); + + if ( isQuad ) { + + faceA = new Face3(); + faceA.a = faces[ offset ]; + faceA.b = faces[ offset + 1 ]; + faceA.c = faces[ offset + 3 ]; + + faceB = new Face3(); + faceB.a = faces[ offset + 1 ]; + faceB.b = faces[ offset + 2 ]; + faceB.c = faces[ offset + 3 ]; + + offset += 4; + + if ( hasMaterial ) { + + materialIndex = faces[ offset ++ ]; + faceA.materialIndex = materialIndex; + faceB.materialIndex = materialIndex; + + } + + // to get face <=> uv index correspondence + + fi = geometry.faces.length; + + if ( hasFaceVertexUv ) { + + for ( i = 0; i < nUvLayers; i ++ ) { + + uvLayer = json.uvs[ i ]; + + geometry.faceVertexUvs[ i ][ fi ] = []; + geometry.faceVertexUvs[ i ][ fi + 1 ] = []; + + for ( j = 0; j < 4; j ++ ) { + + uvIndex = faces[ offset ++ ]; + + u = uvLayer[ uvIndex * 2 ]; + v = uvLayer[ uvIndex * 2 + 1 ]; + + uv = new Vector2( u, v ); + + if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv ); + if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv ); + + } + + } + + } + + if ( hasFaceNormal ) { + + normalIndex = faces[ offset ++ ] * 3; + + faceA.normal.set( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); + + faceB.normal.copy( faceA.normal ); + + } + + if ( hasFaceVertexNormal ) { + + for ( i = 0; i < 4; i ++ ) { + + normalIndex = faces[ offset ++ ] * 3; + + normal = new Vector3( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); + + + if ( i !== 2 ) faceA.vertexNormals.push( normal ); + if ( i !== 0 ) faceB.vertexNormals.push( normal ); + + } + + } + + + if ( hasFaceColor ) { + + colorIndex = faces[ offset ++ ]; + hex = colors[ colorIndex ]; + + faceA.color.setHex( hex ); + faceB.color.setHex( hex ); + + } + + + if ( hasFaceVertexColor ) { + + for ( i = 0; i < 4; i ++ ) { + + colorIndex = faces[ offset ++ ]; + hex = colors[ colorIndex ]; + + if ( i !== 2 ) faceA.vertexColors.push( new Color( hex ) ); + if ( i !== 0 ) faceB.vertexColors.push( new Color( hex ) ); + + } + + } + + geometry.faces.push( faceA ); + geometry.faces.push( faceB ); + + } else { + + face = new Face3(); + face.a = faces[ offset ++ ]; + face.b = faces[ offset ++ ]; + face.c = faces[ offset ++ ]; + + if ( hasMaterial ) { + + materialIndex = faces[ offset ++ ]; + face.materialIndex = materialIndex; + + } + + // to get face <=> uv index correspondence + + fi = geometry.faces.length; + + if ( hasFaceVertexUv ) { + + for ( i = 0; i < nUvLayers; i ++ ) { + + uvLayer = json.uvs[ i ]; + + geometry.faceVertexUvs[ i ][ fi ] = []; + + for ( j = 0; j < 3; j ++ ) { + + uvIndex = faces[ offset ++ ]; + + u = uvLayer[ uvIndex * 2 ]; + v = uvLayer[ uvIndex * 2 + 1 ]; + + uv = new Vector2( u, v ); + + geometry.faceVertexUvs[ i ][ fi ].push( uv ); + + } + + } + + } + + if ( hasFaceNormal ) { + + normalIndex = faces[ offset ++ ] * 3; + + face.normal.set( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); + + } + + if ( hasFaceVertexNormal ) { + + for ( i = 0; i < 3; i ++ ) { + + normalIndex = faces[ offset ++ ] * 3; + + normal = new Vector3( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); + + face.vertexNormals.push( normal ); + + } + + } + + + if ( hasFaceColor ) { + + colorIndex = faces[ offset ++ ]; + face.color.setHex( colors[ colorIndex ] ); + + } + + + if ( hasFaceVertexColor ) { + + for ( i = 0; i < 3; i ++ ) { + + colorIndex = faces[ offset ++ ]; + face.vertexColors.push( new Color( colors[ colorIndex ] ) ); + + } + + } + + geometry.faces.push( face ); + + } + + } + + } + + function parseSkin() { + + var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2; + + if ( json.skinWeights ) { + + for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) { + + var x = json.skinWeights[ i ]; + var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0; + var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0; + var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0; + + geometry.skinWeights.push( new Vector4( x, y, z, w ) ); + + } + + } + + if ( json.skinIndices ) { + + for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) { + + var a = json.skinIndices[ i ]; + var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0; + var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0; + var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0; + + geometry.skinIndices.push( new Vector4( a, b, c, d ) ); + + } + + } + + geometry.bones = json.bones; + + if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { + + console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + + geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); + + } + + } + + function parseMorphing( scale ) { + + if ( json.morphTargets !== undefined ) { + + for ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) { + + geometry.morphTargets[ i ] = {}; + geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; + geometry.morphTargets[ i ].vertices = []; + + var dstVertices = geometry.morphTargets[ i ].vertices; + var srcVertices = json.morphTargets[ i ].vertices; + + for ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) { + + var vertex = new Vector3(); + vertex.x = srcVertices[ v ] * scale; + vertex.y = srcVertices[ v + 1 ] * scale; + vertex.z = srcVertices[ v + 2 ] * scale; + + dstVertices.push( vertex ); + + } + + } + + } + + if ( json.morphColors !== undefined && json.morphColors.length > 0 ) { + + console.warn( 'THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.' ); + + var faces = geometry.faces; + var morphColors = json.morphColors[ 0 ].colors; + + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + faces[ i ].color.fromArray( morphColors, i * 3 ); + + } + + } + + } + + function parseAnimations() { + + var outputAnimations = []; + + // parse old style Bone/Hierarchy animations + var animations = []; + + if ( json.animation !== undefined ) { + + animations.push( json.animation ); + + } + + if ( json.animations !== undefined ) { + + if ( json.animations.length ) { + + animations = animations.concat( json.animations ); + + } else { + + animations.push( json.animations ); + + } + + } + + for ( var i = 0; i < animations.length; i ++ ) { + + var clip = AnimationClip.parseAnimation( animations[ i ], geometry.bones ); + if ( clip ) outputAnimations.push( clip ); + + } + + // parse implicit morph animations + if ( geometry.morphTargets ) { + + // TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary. + var morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 ); + outputAnimations = outputAnimations.concat( morphAnimationClips ); + + } + + if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations; + + } + + if ( json.materials === undefined || json.materials.length === 0 ) { + + return { geometry: geometry }; + + } else { + + var materials = Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin ); + + return { geometry: geometry, materials: materials }; + + } + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function ObjectLoader( manager ) { + + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + this.texturePath = ''; + +} + +Object.assign( ObjectLoader.prototype, { + + load: function ( url, onLoad, onProgress, onError ) { + + if ( this.texturePath === '' ) { + + this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 ); + + } + + var scope = this; + + var loader = new FileLoader( scope.manager ); + loader.load( url, function ( text ) { + + var json = null; + + try { + + json = JSON.parse( text ); + + } catch ( error ) { + + if ( onError !== undefined ) onError( error ); + + console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); + + return; + + } + + var metadata = json.metadata; + + if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { + + console.error( 'THREE.ObjectLoader: Can\'t load ' + url + '. Use THREE.JSONLoader instead.' ); + return; + + } + + scope.parse( json, onLoad ); + + }, onProgress, onError ); + + }, + + setTexturePath: function ( value ) { + + this.texturePath = value; + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + }, + + parse: function ( json, onLoad ) { + + var geometries = this.parseGeometries( json.geometries ); + + var images = this.parseImages( json.images, function () { + + if ( onLoad !== undefined ) onLoad( object ); + + } ); + + var textures = this.parseTextures( json.textures, images ); + var materials = this.parseMaterials( json.materials, textures ); + + var object = this.parseObject( json.object, geometries, materials ); + + if ( json.animations ) { + + object.animations = this.parseAnimations( json.animations ); + + } + + if ( json.images === undefined || json.images.length === 0 ) { + + if ( onLoad !== undefined ) onLoad( object ); + + } + + return object; + + }, + + parseGeometries: function ( json ) { + + var geometries = {}; + + if ( json !== undefined ) { + + var geometryLoader = new JSONLoader(); + var bufferGeometryLoader = new BufferGeometryLoader(); + + for ( var i = 0, l = json.length; i < l; i ++ ) { + + var geometry; + var data = json[ i ]; + + switch ( data.type ) { + + case 'PlaneGeometry': + case 'PlaneBufferGeometry': + + geometry = new Geometries[ data.type ]( + data.width, + data.height, + data.widthSegments, + data.heightSegments + ); + + break; + + case 'BoxGeometry': + case 'BoxBufferGeometry': + case 'CubeGeometry': // backwards compatible + + geometry = new Geometries[ data.type ]( + data.width, + data.height, + data.depth, + data.widthSegments, + data.heightSegments, + data.depthSegments + ); + + break; + + case 'CircleGeometry': + case 'CircleBufferGeometry': + + geometry = new Geometries[ data.type ]( + data.radius, + data.segments, + data.thetaStart, + data.thetaLength + ); + + break; + + case 'CylinderGeometry': + case 'CylinderBufferGeometry': + + geometry = new Geometries[ data.type ]( + data.radiusTop, + data.radiusBottom, + data.height, + data.radialSegments, + data.heightSegments, + data.openEnded, + data.thetaStart, + data.thetaLength + ); + + break; + + case 'ConeGeometry': + case 'ConeBufferGeometry': + + geometry = new Geometries[ data.type ]( + data.radius, + data.height, + data.radialSegments, + data.heightSegments, + data.openEnded, + data.thetaStart, + data.thetaLength + ); + + break; + + case 'SphereGeometry': + case 'SphereBufferGeometry': + + geometry = new Geometries[ data.type ]( + data.radius, + data.widthSegments, + data.heightSegments, + data.phiStart, + data.phiLength, + data.thetaStart, + data.thetaLength + ); + + break; + + case 'DodecahedronGeometry': + case 'IcosahedronGeometry': + case 'OctahedronGeometry': + case 'TetrahedronGeometry': + + geometry = new Geometries[ data.type ]( + data.radius, + data.detail + ); + + break; + + case 'RingGeometry': + case 'RingBufferGeometry': + + geometry = new Geometries[ data.type ]( + data.innerRadius, + data.outerRadius, + data.thetaSegments, + data.phiSegments, + data.thetaStart, + data.thetaLength + ); + + break; + + case 'TorusGeometry': + case 'TorusBufferGeometry': + + geometry = new Geometries[ data.type ]( + data.radius, + data.tube, + data.radialSegments, + data.tubularSegments, + data.arc + ); + + break; + + case 'TorusKnotGeometry': + case 'TorusKnotBufferGeometry': + + geometry = new Geometries[ data.type ]( + data.radius, + data.tube, + data.tubularSegments, + data.radialSegments, + data.p, + data.q + ); + + break; + + case 'LatheGeometry': + case 'LatheBufferGeometry': + + geometry = new Geometries[ data.type ]( + data.points, + data.segments, + data.phiStart, + data.phiLength + ); + + break; + + case 'BufferGeometry': + + geometry = bufferGeometryLoader.parse( data ); + + break; + + case 'Geometry': + + geometry = geometryLoader.parse( data.data, this.texturePath ).geometry; + + break; + + default: + + console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' ); + + continue; + + } + + geometry.uuid = data.uuid; + + if ( data.name !== undefined ) geometry.name = data.name; + + geometries[ data.uuid ] = geometry; + + } + + } + + return geometries; + + }, + + parseMaterials: function ( json, textures ) { + + var materials = {}; + + if ( json !== undefined ) { + + var loader = new MaterialLoader(); + loader.setTextures( textures ); + + for ( var i = 0, l = json.length; i < l; i ++ ) { + + var material = loader.parse( json[ i ] ); + materials[ material.uuid ] = material; + + } + + } + + return materials; + + }, + + parseAnimations: function ( json ) { + + var animations = []; + + for ( var i = 0; i < json.length; i ++ ) { + + var clip = AnimationClip.parse( json[ i ] ); + + animations.push( clip ); + + } + + return animations; + + }, + + parseImages: function ( json, onLoad ) { + + var scope = this; + var images = {}; + + function loadImage( url ) { + + scope.manager.itemStart( url ); + + return loader.load( url, function () { + + scope.manager.itemEnd( url ); + + }, undefined, function () { + + scope.manager.itemError( url ); + + } ); + + } + + if ( json !== undefined && json.length > 0 ) { + + var manager = new LoadingManager( onLoad ); + + var loader = new ImageLoader( manager ); + loader.setCrossOrigin( this.crossOrigin ); + + for ( var i = 0, l = json.length; i < l; i ++ ) { + + var image = json[ i ]; + var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url; + + images[ image.uuid ] = loadImage( path ); + + } + + } + + return images; + + }, + + parseTextures: function ( json, images ) { + + var TextureMapping = { + UVMapping: UVMapping, + CubeReflectionMapping: CubeReflectionMapping, + CubeRefractionMapping: CubeRefractionMapping, + EquirectangularReflectionMapping: EquirectangularReflectionMapping, + EquirectangularRefractionMapping: EquirectangularRefractionMapping, + SphericalReflectionMapping: SphericalReflectionMapping, + CubeUVReflectionMapping: CubeUVReflectionMapping, + CubeUVRefractionMapping: CubeUVRefractionMapping + }; + + var TextureWrapping = { + RepeatWrapping: RepeatWrapping, + ClampToEdgeWrapping: ClampToEdgeWrapping, + MirroredRepeatWrapping: MirroredRepeatWrapping + }; + + var TextureFilter = { + NearestFilter: NearestFilter, + NearestMipMapNearestFilter: NearestMipMapNearestFilter, + NearestMipMapLinearFilter: NearestMipMapLinearFilter, + LinearFilter: LinearFilter, + LinearMipMapNearestFilter: LinearMipMapNearestFilter, + LinearMipMapLinearFilter: LinearMipMapLinearFilter + }; + + function parseConstant( value, type ) { + + if ( typeof( value ) === 'number' ) return value; + + console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); + + return type[ value ]; + + } + + var textures = {}; + + if ( json !== undefined ) { + + for ( var i = 0, l = json.length; i < l; i ++ ) { + + var data = json[ i ]; + + if ( data.image === undefined ) { + + console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); + + } + + if ( images[ data.image ] === undefined ) { + + console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); + + } + + var texture = new Texture( images[ data.image ] ); + texture.needsUpdate = true; + + texture.uuid = data.uuid; + + if ( data.name !== undefined ) texture.name = data.name; + + if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TextureMapping ); + + if ( data.offset !== undefined ) texture.offset.fromArray( data.offset ); + if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat ); + if ( data.wrap !== undefined ) { + + texture.wrapS = parseConstant( data.wrap[ 0 ], TextureWrapping ); + texture.wrapT = parseConstant( data.wrap[ 1 ], TextureWrapping ); + + } + + if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TextureFilter ); + if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TextureFilter ); + if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; + + if ( data.flipY !== undefined ) texture.flipY = data.flipY; + + textures[ data.uuid ] = texture; + + } + + } + + return textures; + + }, + + parseObject: function () { + + var matrix = new Matrix4(); + + return function parseObject( data, geometries, materials ) { + + var object; + + function getGeometry( name ) { + + if ( geometries[ name ] === undefined ) { + + console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); + + } + + return geometries[ name ]; + + } + + function getMaterial( name ) { + + if ( name === undefined ) return undefined; + + if ( materials[ name ] === undefined ) { + + console.warn( 'THREE.ObjectLoader: Undefined material', name ); + + } + + return materials[ name ]; + + } + + switch ( data.type ) { + + case 'Scene': + + object = new Scene(); + + if ( data.background !== undefined ) { + + if ( Number.isInteger( data.background ) ) { + + object.background = new Color( data.background ); + + } + + } + + if ( data.fog !== undefined ) { + + if ( data.fog.type === 'Fog' ) { + + object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); + + } else if ( data.fog.type === 'FogExp2' ) { + + object.fog = new FogExp2( data.fog.color, data.fog.density ); + + } + + } + + break; + + case 'PerspectiveCamera': + + object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); + + if ( data.focus !== undefined ) object.focus = data.focus; + if ( data.zoom !== undefined ) object.zoom = data.zoom; + if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge; + if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset; + if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); + + break; + + case 'OrthographicCamera': + + object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); + + break; + + case 'AmbientLight': + + object = new AmbientLight( data.color, data.intensity ); + + break; + + case 'DirectionalLight': + + object = new DirectionalLight( data.color, data.intensity ); + + break; + + case 'PointLight': + + object = new PointLight( data.color, data.intensity, data.distance, data.decay ); + + break; + + case 'SpotLight': + + object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); + + break; + + case 'HemisphereLight': + + object = new HemisphereLight( data.color, data.groundColor, data.intensity ); + + break; + + case 'Mesh': + + var geometry = getGeometry( data.geometry ); + var material = getMaterial( data.material ); + + if ( geometry.bones && geometry.bones.length > 0 ) { + + object = new SkinnedMesh( geometry, material ); + + } else { + + object = new Mesh( geometry, material ); + + } + + break; + + case 'LOD': + + object = new LOD(); + + break; + + case 'Line': + + object = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); + + break; + + case 'LineSegments': + + object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); + + break; + + case 'PointCloud': + case 'Points': + + object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); + + break; + + case 'Sprite': + + object = new Sprite( getMaterial( data.material ) ); + + break; + + case 'Group': + + object = new Group(); + + break; + + case 'SkinnedMesh': + + console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh type. Instantiates Object3D instead.' ); + + default: + + object = new Object3D(); + + } + + object.uuid = data.uuid; + + if ( data.name !== undefined ) object.name = data.name; + if ( data.matrix !== undefined ) { + + matrix.fromArray( data.matrix ); + matrix.decompose( object.position, object.quaternion, object.scale ); + + } else { + + if ( data.position !== undefined ) object.position.fromArray( data.position ); + if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); + if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); + if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); + + } + + if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; + if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; + + if ( data.shadow ) { + + if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; + if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; + if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); + if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); + + } + + if ( data.visible !== undefined ) object.visible = data.visible; + if ( data.userData !== undefined ) object.userData = data.userData; + + if ( data.children !== undefined ) { + + for ( var child in data.children ) { + + object.add( this.parseObject( data.children[ child ], geometries, materials ) ); + + } + + } + + if ( data.type === 'LOD' ) { + + var levels = data.levels; + + for ( var l = 0; l < levels.length; l ++ ) { + + var level = levels[ l ]; + var child = object.getObjectByProperty( 'uuid', level.object ); + + if ( child !== undefined ) { + + object.addLevel( child, level.distance ); + + } + + } + + } + + return object; + + }; + + }() + +} ); + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * + * Bezier Curves formulas obtained from + * http://en.wikipedia.org/wiki/Bézier_curve + */ + +function CatmullRom( t, p0, p1, p2, p3 ) { + + var v0 = ( p2 - p0 ) * 0.5; + var v1 = ( p3 - p1 ) * 0.5; + var t2 = t * t; + var t3 = t * t2; + return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; + +} + +// + +function QuadraticBezierP0( t, p ) { + + var k = 1 - t; + return k * k * p; + +} + +function QuadraticBezierP1( t, p ) { + + return 2 * ( 1 - t ) * t * p; + +} + +function QuadraticBezierP2( t, p ) { + + return t * t * p; + +} + +function QuadraticBezier( t, p0, p1, p2 ) { + + return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + + QuadraticBezierP2( t, p2 ); + +} + +// + +function CubicBezierP0( t, p ) { + + var k = 1 - t; + return k * k * k * p; + +} + +function CubicBezierP1( t, p ) { + + var k = 1 - t; + return 3 * k * k * t * p; + +} + +function CubicBezierP2( t, p ) { + + return 3 * ( 1 - t ) * t * t * p; + +} + +function CubicBezierP3( t, p ) { + + return t * t * t * p; + +} + +function CubicBezier( t, p0, p1, p2, p3 ) { + + return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + + CubicBezierP3( t, p3 ); + +} + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Extensible curve object + * + * Some common of Curve methods + * .getPoint(t), getTangent(t) + * .getPointAt(u), getTangentAt(u) + * .getPoints(), .getSpacedPoints() + * .getLength() + * .updateArcLengths() + * + * This following classes subclasses THREE.Curve: + * + * -- 2d classes -- + * THREE.LineCurve + * THREE.QuadraticBezierCurve + * THREE.CubicBezierCurve + * THREE.SplineCurve + * THREE.ArcCurve + * THREE.EllipseCurve + * + * -- 3d classes -- + * THREE.LineCurve3 + * THREE.QuadraticBezierCurve3 + * THREE.CubicBezierCurve3 + * THREE.CatmullRomCurve3 + * + * A series of curves can be represented as a THREE.CurvePath + * + **/ + +/************************************************************** + * Abstract Curve base class + **************************************************************/ + +function Curve() {} + +Curve.prototype = { + + constructor: Curve, + + // Virtual base class method to overwrite and implement in subclasses + // - t [0 .. 1] + + getPoint: function ( t ) { + + console.warn( "THREE.Curve: Warning, getPoint() not implemented!" ); + return null; + + }, + + // Get point at relative position in curve according to arc length + // - u [0 .. 1] + + getPointAt: function ( u ) { + + var t = this.getUtoTmapping( u ); + return this.getPoint( t ); + + }, + + // Get sequence of points using getPoint( t ) + + getPoints: function ( divisions ) { + + if ( isNaN( divisions ) ) divisions = 5; + + var points = []; + + for ( var d = 0; d <= divisions; d ++ ) { + + points.push( this.getPoint( d / divisions ) ); + + } + + return points; + + }, + + // Get sequence of points using getPointAt( u ) + + getSpacedPoints: function ( divisions ) { + + if ( isNaN( divisions ) ) divisions = 5; + + var points = []; + + for ( var d = 0; d <= divisions; d ++ ) { + + points.push( this.getPointAt( d / divisions ) ); + + } + + return points; + + }, + + // Get total curve arc length + + getLength: function () { + + var lengths = this.getLengths(); + return lengths[ lengths.length - 1 ]; + + }, + + // Get list of cumulative segment lengths + + getLengths: function ( divisions ) { + + if ( isNaN( divisions ) ) divisions = ( this.__arcLengthDivisions ) ? ( this.__arcLengthDivisions ) : 200; + + if ( this.cacheArcLengths + && ( this.cacheArcLengths.length === divisions + 1 ) + && ! this.needsUpdate ) { + + //console.log( "cached", this.cacheArcLengths ); + return this.cacheArcLengths; + + } + + this.needsUpdate = false; + + var cache = []; + var current, last = this.getPoint( 0 ); + var p, sum = 0; + + cache.push( 0 ); + + for ( p = 1; p <= divisions; p ++ ) { + + current = this.getPoint ( p / divisions ); + sum += current.distanceTo( last ); + cache.push( sum ); + last = current; + + } + + this.cacheArcLengths = cache; + + return cache; // { sums: cache, sum:sum }; Sum is in the last element. + + }, + + updateArcLengths: function() { + + this.needsUpdate = true; + this.getLengths(); + + }, + + // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant + + getUtoTmapping: function ( u, distance ) { + + var arcLengths = this.getLengths(); + + var i = 0, il = arcLengths.length; + + var targetArcLength; // The targeted u distance value to get + + if ( distance ) { + + targetArcLength = distance; + + } else { + + targetArcLength = u * arcLengths[ il - 1 ]; + + } + + //var time = Date.now(); + + // binary search for the index with largest value smaller than target u distance + + var low = 0, high = il - 1, comparison; + + while ( low <= high ) { + + i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats + + comparison = arcLengths[ i ] - targetArcLength; + + if ( comparison < 0 ) { + + low = i + 1; + + } else if ( comparison > 0 ) { + + high = i - 1; + + } else { + + high = i; + break; + + // DONE + + } + + } + + i = high; + + //console.log('b' , i, low, high, Date.now()- time); + + if ( arcLengths[ i ] === targetArcLength ) { + + var t = i / ( il - 1 ); + return t; + + } + + // we could get finer grain at lengths, or use simple interpolation between two points + + var lengthBefore = arcLengths[ i ]; + var lengthAfter = arcLengths[ i + 1 ]; + + var segmentLength = lengthAfter - lengthBefore; + + // determine where we are between the 'before' and 'after' points + + var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; + + // add that fractional amount to t + + var t = ( i + segmentFraction ) / ( il - 1 ); + + return t; + + }, + + // Returns a unit vector tangent at t + // In case any sub curve does not implement its tangent derivation, + // 2 points a small delta apart will be used to find its gradient + // which seems to give a reasonable approximation + + getTangent: function( t ) { + + var delta = 0.0001; + var t1 = t - delta; + var t2 = t + delta; + + // Capping in case of danger + + if ( t1 < 0 ) t1 = 0; + if ( t2 > 1 ) t2 = 1; + + var pt1 = this.getPoint( t1 ); + var pt2 = this.getPoint( t2 ); + + var vec = pt2.clone().sub( pt1 ); + return vec.normalize(); + + }, + + getTangentAt: function ( u ) { + + var t = this.getUtoTmapping( u ); + return this.getTangent( t ); + + }, + + computeFrenetFrames: function ( segments, closed ) { + + // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf + + var normal = new Vector3(); + + var tangents = []; + var normals = []; + var binormals = []; + + var vec = new Vector3(); + var mat = new Matrix4(); + + var i, u, theta; + + // compute the tangent vectors for each segment on the curve + + for ( i = 0; i <= segments; i ++ ) { + + u = i / segments; + + tangents[ i ] = this.getTangentAt( u ); + tangents[ i ].normalize(); + + } + + // select an initial normal vector perpendicular to the first tangent vector, + // and in the direction of the minimum tangent xyz component + + normals[ 0 ] = new Vector3(); + binormals[ 0 ] = new Vector3(); + var min = Number.MAX_VALUE; + var tx = Math.abs( tangents[ 0 ].x ); + var ty = Math.abs( tangents[ 0 ].y ); + var tz = Math.abs( tangents[ 0 ].z ); + + if ( tx <= min ) { + + min = tx; + normal.set( 1, 0, 0 ); + + } + + if ( ty <= min ) { + + min = ty; + normal.set( 0, 1, 0 ); + + } + + if ( tz <= min ) { + + normal.set( 0, 0, 1 ); + + } + + vec.crossVectors( tangents[ 0 ], normal ).normalize(); + + normals[ 0 ].crossVectors( tangents[ 0 ], vec ); + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); + + + // compute the slowly-varying normal and binormal vectors for each segment on the curve + + for ( i = 1; i <= segments; i ++ ) { + + normals[ i ] = normals[ i - 1 ].clone(); + + binormals[ i ] = binormals[ i - 1 ].clone(); + + vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); + + if ( vec.length() > Number.EPSILON ) { + + vec.normalize(); + + theta = Math.acos( _Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors + + normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); + + } + + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + + } + + // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same + + if ( closed === true ) { + + theta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); + theta /= segments; + + if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { + + theta = - theta; + + } + + for ( i = 1; i <= segments; i ++ ) { + + // twist a little... + normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + + } + + } + + return { + tangents: tangents, + normals: normals, + binormals: binormals + }; + + } + +}; + +function LineCurve( v1, v2 ) { + + this.v1 = v1; + this.v2 = v2; + +} + +LineCurve.prototype = Object.create( Curve.prototype ); +LineCurve.prototype.constructor = LineCurve; + +LineCurve.prototype.isLineCurve = true; + +LineCurve.prototype.getPoint = function ( t ) { + + if ( t === 1 ) { + + return this.v2.clone(); + + } + + var point = this.v2.clone().sub( this.v1 ); + point.multiplyScalar( t ).add( this.v1 ); + + return point; + +}; + +// Line curve is linear, so we can overwrite default getPointAt + +LineCurve.prototype.getPointAt = function ( u ) { + + return this.getPoint( u ); + +}; + +LineCurve.prototype.getTangent = function ( t ) { + + var tangent = this.v2.clone().sub( this.v1 ); + + return tangent.normalize(); + +}; + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * + **/ + +/************************************************************** + * Curved Path - a curve path is simply a array of connected + * curves, but retains the api of a curve + **************************************************************/ + +function CurvePath() { + + this.curves = []; + + this.autoClose = false; // Automatically closes the path + +} + +CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), { + + constructor: CurvePath, + + add: function ( curve ) { + + this.curves.push( curve ); + + }, + + closePath: function () { + + // Add a line curve if start and end of lines are not connected + var startPoint = this.curves[ 0 ].getPoint( 0 ); + var endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); + + if ( ! startPoint.equals( endPoint ) ) { + + this.curves.push( new LineCurve( endPoint, startPoint ) ); + + } + + }, + + // To get accurate point with reference to + // entire path distance at time t, + // following has to be done: + + // 1. Length of each sub path have to be known + // 2. Locate and identify type of curve + // 3. Get t for the curve + // 4. Return curve.getPointAt(t') + + getPoint: function ( t ) { + + var d = t * this.getLength(); + var curveLengths = this.getCurveLengths(); + var i = 0; + + // To think about boundaries points. + + while ( i < curveLengths.length ) { + + if ( curveLengths[ i ] >= d ) { + + var diff = curveLengths[ i ] - d; + var curve = this.curves[ i ]; + + var segmentLength = curve.getLength(); + var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; + + return curve.getPointAt( u ); + + } + + i ++; + + } + + return null; + + // loop where sum != 0, sum > d , sum+1 1 && !points[ points.length - 1 ].equals( points[ 0 ] ) ) { + + points.push( points[ 0 ] ); + + } + + return points; + + }, + + /************************************************************** + * Create Geometries Helpers + **************************************************************/ + + /// Generate geometry from path points (for Line or Points objects) + + createPointsGeometry: function ( divisions ) { + + var pts = this.getPoints( divisions ); + return this.createGeometry( pts ); + + }, + + // Generate geometry from equidistant sampling along the path + + createSpacedPointsGeometry: function ( divisions ) { + + var pts = this.getSpacedPoints( divisions ); + return this.createGeometry( pts ); + + }, + + createGeometry: function ( points ) { + + var geometry = new Geometry(); + + for ( var i = 0, l = points.length; i < l; i ++ ) { + + var point = points[ i ]; + geometry.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) ); + + } + + return geometry; + + } + +} ); + +function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { + + this.aX = aX; + this.aY = aY; + + this.xRadius = xRadius; + this.yRadius = yRadius; + + this.aStartAngle = aStartAngle; + this.aEndAngle = aEndAngle; + + this.aClockwise = aClockwise; + + this.aRotation = aRotation || 0; + +} + +EllipseCurve.prototype = Object.create( Curve.prototype ); +EllipseCurve.prototype.constructor = EllipseCurve; + +EllipseCurve.prototype.isEllipseCurve = true; + +EllipseCurve.prototype.getPoint = function ( t ) { + + var twoPi = Math.PI * 2; + var deltaAngle = this.aEndAngle - this.aStartAngle; + var samePoints = Math.abs( deltaAngle ) < Number.EPSILON; + + // ensures that deltaAngle is 0 .. 2 PI + while ( deltaAngle < 0 ) deltaAngle += twoPi; + while ( deltaAngle > twoPi ) deltaAngle -= twoPi; + + if ( deltaAngle < Number.EPSILON ) { + + if ( samePoints ) { + + deltaAngle = 0; + + } else { + + deltaAngle = twoPi; + + } + + } + + if ( this.aClockwise === true && ! samePoints ) { + + if ( deltaAngle === twoPi ) { + + deltaAngle = - twoPi; + + } else { + + deltaAngle = deltaAngle - twoPi; + + } + + } + + var angle = this.aStartAngle + t * deltaAngle; + var x = this.aX + this.xRadius * Math.cos( angle ); + var y = this.aY + this.yRadius * Math.sin( angle ); + + if ( this.aRotation !== 0 ) { + + var cos = Math.cos( this.aRotation ); + var sin = Math.sin( this.aRotation ); + + var tx = x - this.aX; + var ty = y - this.aY; + + // Rotate the point about the center of the ellipse. + x = tx * cos - ty * sin + this.aX; + y = tx * sin + ty * cos + this.aY; + + } + + return new Vector2( x, y ); + +}; + +function SplineCurve( points /* array of Vector2 */ ) { + + this.points = ( points === undefined ) ? [] : points; + +} + +SplineCurve.prototype = Object.create( Curve.prototype ); +SplineCurve.prototype.constructor = SplineCurve; + +SplineCurve.prototype.isSplineCurve = true; + +SplineCurve.prototype.getPoint = function ( t ) { + + var points = this.points; + var point = ( points.length - 1 ) * t; + + var intPoint = Math.floor( point ); + var weight = point - intPoint; + + var point0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; + var point1 = points[ intPoint ]; + var point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; + var point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; + + return new Vector2( + CatmullRom( weight, point0.x, point1.x, point2.x, point3.x ), + CatmullRom( weight, point0.y, point1.y, point2.y, point3.y ) + ); + +}; + +function CubicBezierCurve( v0, v1, v2, v3 ) { + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + +} + +CubicBezierCurve.prototype = Object.create( Curve.prototype ); +CubicBezierCurve.prototype.constructor = CubicBezierCurve; + +CubicBezierCurve.prototype.getPoint = function ( t ) { + + var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; + + return new Vector2( + CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), + CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) + ); + +}; + +function QuadraticBezierCurve( v0, v1, v2 ) { + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + +} + +QuadraticBezierCurve.prototype = Object.create( Curve.prototype ); +QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve; + +QuadraticBezierCurve.prototype.getPoint = function ( t ) { + + var v0 = this.v0, v1 = this.v1, v2 = this.v2; + + return new Vector2( + QuadraticBezier( t, v0.x, v1.x, v2.x ), + QuadraticBezier( t, v0.y, v1.y, v2.y ) + ); + +}; + +var PathPrototype = Object.assign( Object.create( CurvePath.prototype ), { + + fromPoints: function ( vectors ) { + + this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y ); + + for ( var i = 1, l = vectors.length; i < l; i ++ ) { + + this.lineTo( vectors[ i ].x, vectors[ i ].y ); + + } + + }, + + moveTo: function ( x, y ) { + + this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? + + }, + + lineTo: function ( x, y ) { + + var curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); + this.curves.push( curve ); + + this.currentPoint.set( x, y ); + + }, + + quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { + + var curve = new QuadraticBezierCurve( + this.currentPoint.clone(), + new Vector2( aCPx, aCPy ), + new Vector2( aX, aY ) + ); + + this.curves.push( curve ); + + this.currentPoint.set( aX, aY ); + + }, + + bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { + + var curve = new CubicBezierCurve( + this.currentPoint.clone(), + new Vector2( aCP1x, aCP1y ), + new Vector2( aCP2x, aCP2y ), + new Vector2( aX, aY ) + ); + + this.curves.push( curve ); + + this.currentPoint.set( aX, aY ); + + }, + + splineThru: function ( pts /*Array of Vector*/ ) { + + var npts = [ this.currentPoint.clone() ].concat( pts ); + + var curve = new SplineCurve( npts ); + this.curves.push( curve ); + + this.currentPoint.copy( pts[ pts.length - 1 ] ); + + }, + + arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + + var x0 = this.currentPoint.x; + var y0 = this.currentPoint.y; + + this.absarc( aX + x0, aY + y0, aRadius, + aStartAngle, aEndAngle, aClockwise ); + + }, + + absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + + this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); + + }, + + ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { + + var x0 = this.currentPoint.x; + var y0 = this.currentPoint.y; + + this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); + + }, + + absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { + + var curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); + + if ( this.curves.length > 0 ) { + + // if a previous curve is present, attempt to join + var firstPoint = curve.getPoint( 0 ); + + if ( ! firstPoint.equals( this.currentPoint ) ) { + + this.lineTo( firstPoint.x, firstPoint.y ); + + } + + } + + this.curves.push( curve ); + + var lastPoint = curve.getPoint( 1 ); + this.currentPoint.copy( lastPoint ); + + } + +} ); + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Creates free form 2d path using series of points, lines or curves. + **/ + +function Path( points ) { + + CurvePath.call( this ); + this.currentPoint = new Vector2(); + + if ( points ) { + + this.fromPoints( points ); + + } + +} + +Path.prototype = PathPrototype; +PathPrototype.constructor = Path; + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Defines a 2d shape plane using paths. + **/ + +// STEP 1 Create a path. +// STEP 2 Turn path into shape. +// STEP 3 ExtrudeGeometry takes in Shape/Shapes +// STEP 3a - Extract points from each shape, turn to vertices +// STEP 3b - Triangulate each shape, add faces. + +function Shape() { + + Path.apply( this, arguments ); + + this.holes = []; + +} + +Shape.prototype = Object.assign( Object.create( PathPrototype ), { + + constructor: Shape, + + getPointsHoles: function ( divisions ) { + + var holesPts = []; + + for ( var i = 0, l = this.holes.length; i < l; i ++ ) { + + holesPts[ i ] = this.holes[ i ].getPoints( divisions ); + + } + + return holesPts; + + }, + + // Get points of shape and holes (keypoints based on segments parameter) + + extractAllPoints: function ( divisions ) { + + return { + + shape: this.getPoints( divisions ), + holes: this.getPointsHoles( divisions ) + + }; + + }, + + extractPoints: function ( divisions ) { + + return this.extractAllPoints( divisions ); + + } + +} ); + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * minimal class for proxing functions to Path. Replaces old "extractSubpaths()" + **/ + +function ShapePath() { + + this.subPaths = []; + this.currentPath = null; + +} + +ShapePath.prototype = { + + moveTo: function ( x, y ) { + + this.currentPath = new Path(); + this.subPaths.push( this.currentPath ); + this.currentPath.moveTo( x, y ); + + }, + + lineTo: function ( x, y ) { + + this.currentPath.lineTo( x, y ); + + }, + + quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { + + this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY ); + + }, + + bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { + + this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ); + + }, + + splineThru: function ( pts ) { + + this.currentPath.splineThru( pts ); + + }, + + toShapes: function ( isCCW, noHoles ) { + + function toShapesNoHoles( inSubpaths ) { + + var shapes = []; + + for ( var i = 0, l = inSubpaths.length; i < l; i ++ ) { + + var tmpPath = inSubpaths[ i ]; + + var tmpShape = new Shape(); + tmpShape.curves = tmpPath.curves; + + shapes.push( tmpShape ); + + } + + return shapes; + + } + + function isPointInsidePolygon( inPt, inPolygon ) { + + var polyLen = inPolygon.length; + + // inPt on polygon contour => immediate success or + // toggling of inside/outside at every single! intersection point of an edge + // with the horizontal line through inPt, left of inPt + // not counting lowerY endpoints of edges and whole edges on that line + var inside = false; + for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { + + var edgeLowPt = inPolygon[ p ]; + var edgeHighPt = inPolygon[ q ]; + + var edgeDx = edgeHighPt.x - edgeLowPt.x; + var edgeDy = edgeHighPt.y - edgeLowPt.y; + + if ( Math.abs( edgeDy ) > Number.EPSILON ) { + + // not parallel + if ( edgeDy < 0 ) { + + edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; + edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; + + } + if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; + + if ( inPt.y === edgeLowPt.y ) { + + if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? + // continue; // no intersection or edgeLowPt => doesn't count !!! + + } else { + + var perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y ); + if ( perpEdge === 0 ) return true; // inPt is on contour ? + if ( perpEdge < 0 ) continue; + inside = ! inside; // true intersection left of inPt + + } + + } else { + + // parallel or collinear + if ( inPt.y !== edgeLowPt.y ) continue; // parallel + // edge lies on the same horizontal line as inPt + if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || + ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! + // continue; + + } + + } + + return inside; + + } + + var isClockWise = ShapeUtils.isClockWise; + + var subPaths = this.subPaths; + if ( subPaths.length === 0 ) return []; + + if ( noHoles === true ) return toShapesNoHoles( subPaths ); + + + var solid, tmpPath, tmpShape, shapes = []; + + if ( subPaths.length === 1 ) { + + tmpPath = subPaths[ 0 ]; + tmpShape = new Shape(); + tmpShape.curves = tmpPath.curves; + shapes.push( tmpShape ); + return shapes; + + } + + var holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() ); + holesFirst = isCCW ? ! holesFirst : holesFirst; + + // console.log("Holes first", holesFirst); + + var betterShapeHoles = []; + var newShapes = []; + var newShapeHoles = []; + var mainIdx = 0; + var tmpPoints; + + newShapes[ mainIdx ] = undefined; + newShapeHoles[ mainIdx ] = []; + + for ( var i = 0, l = subPaths.length; i < l; i ++ ) { + + tmpPath = subPaths[ i ]; + tmpPoints = tmpPath.getPoints(); + solid = isClockWise( tmpPoints ); + solid = isCCW ? ! solid : solid; + + if ( solid ) { + + if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++; + + newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints }; + newShapes[ mainIdx ].s.curves = tmpPath.curves; + + if ( holesFirst ) mainIdx ++; + newShapeHoles[ mainIdx ] = []; + + //console.log('cw', i); + + } else { + + newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); + + //console.log('ccw', i); + + } + + } + + // only Holes? -> probably all Shapes with wrong orientation + if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); + + + if ( newShapes.length > 1 ) { + + var ambiguous = false; + var toChange = []; + + for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { + + betterShapeHoles[ sIdx ] = []; + + } + + for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { + + var sho = newShapeHoles[ sIdx ]; + + for ( var hIdx = 0; hIdx < sho.length; hIdx ++ ) { + + var ho = sho[ hIdx ]; + var hole_unassigned = true; + + for ( var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { + + if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { + + if ( sIdx !== s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } ); + if ( hole_unassigned ) { + + hole_unassigned = false; + betterShapeHoles[ s2Idx ].push( ho ); + + } else { + + ambiguous = true; + + } + + } + + } + if ( hole_unassigned ) { + + betterShapeHoles[ sIdx ].push( ho ); + + } + + } + + } + // console.log("ambiguous: ", ambiguous); + if ( toChange.length > 0 ) { + + // console.log("to change: ", toChange); + if ( ! ambiguous ) newShapeHoles = betterShapeHoles; + + } + + } + + var tmpHoles; + + for ( var i = 0, il = newShapes.length; i < il; i ++ ) { + + tmpShape = newShapes[ i ].s; + shapes.push( tmpShape ); + tmpHoles = newShapeHoles[ i ]; + + for ( var j = 0, jl = tmpHoles.length; j < jl; j ++ ) { + + tmpShape.holes.push( tmpHoles[ j ].h ); + + } + + } + + //console.log("shape", shapes); + + return shapes; + + } + +}; + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * @author mrdoob / http://mrdoob.com/ + */ + +function Font( data ) { + + this.data = data; + +} + +Object.assign( Font.prototype, { + + isFont: true, + + generateShapes: function ( text, size, divisions ) { + + function createPaths( text ) { + + var chars = String( text ).split( '' ); + var scale = size / data.resolution; + var line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale; + + var offsetX = 0, offsetY = 0; + + var paths = []; + + for ( var i = 0; i < chars.length; i ++ ) { + + var char = chars[ i ]; + + if ( char === '\n' ) { + + offsetX = 0; + offsetY -= line_height; + + } else { + + var ret = createPath( char, scale, offsetX, offsetY ); + offsetX += ret.offsetX; + paths.push( ret.path ); + + } + + } + + return paths; + + } + + function createPath( c, scale, offsetX, offsetY ) { + + var glyph = data.glyphs[ c ] || data.glyphs[ '?' ]; + + if ( ! glyph ) return; + + var path = new ShapePath(); + + var pts = []; + var x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, laste; + + if ( glyph.o ) { + + var outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); + + for ( var i = 0, l = outline.length; i < l; ) { + + var action = outline[ i ++ ]; + + switch ( action ) { + + case 'm': // moveTo + + x = outline[ i ++ ] * scale + offsetX; + y = outline[ i ++ ] * scale + offsetY; + + path.moveTo( x, y ); + + break; + + case 'l': // lineTo + + x = outline[ i ++ ] * scale + offsetX; + y = outline[ i ++ ] * scale + offsetY; + + path.lineTo( x, y ); + + break; + + case 'q': // quadraticCurveTo + + cpx = outline[ i ++ ] * scale + offsetX; + cpy = outline[ i ++ ] * scale + offsetY; + cpx1 = outline[ i ++ ] * scale + offsetX; + cpy1 = outline[ i ++ ] * scale + offsetY; + + path.quadraticCurveTo( cpx1, cpy1, cpx, cpy ); + + laste = pts[ pts.length - 1 ]; + + if ( laste ) { + + cpx0 = laste.x; + cpy0 = laste.y; + + for ( var i2 = 1; i2 <= divisions; i2 ++ ) { + + var t = i2 / divisions; + QuadraticBezier( t, cpx0, cpx1, cpx ); + QuadraticBezier( t, cpy0, cpy1, cpy ); + + } + + } + + break; + + case 'b': // bezierCurveTo + + cpx = outline[ i ++ ] * scale + offsetX; + cpy = outline[ i ++ ] * scale + offsetY; + cpx1 = outline[ i ++ ] * scale + offsetX; + cpy1 = outline[ i ++ ] * scale + offsetY; + cpx2 = outline[ i ++ ] * scale + offsetX; + cpy2 = outline[ i ++ ] * scale + offsetY; + + path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy ); + + laste = pts[ pts.length - 1 ]; + + if ( laste ) { + + cpx0 = laste.x; + cpy0 = laste.y; + + for ( var i2 = 1; i2 <= divisions; i2 ++ ) { + + var t = i2 / divisions; + CubicBezier( t, cpx0, cpx1, cpx2, cpx ); + CubicBezier( t, cpy0, cpy1, cpy2, cpy ); + + } + + } + + break; + + } + + } + + } + + return { offsetX: glyph.ha * scale, path: path }; + + } + + // + + if ( size === undefined ) size = 100; + if ( divisions === undefined ) divisions = 4; + + var data = this.data; + + var paths = createPaths( text ); + var shapes = []; + + for ( var p = 0, pl = paths.length; p < pl; p ++ ) { + + Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); + + } + + return shapes; + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function FontLoader( manager ) { + + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + +} + +Object.assign( FontLoader.prototype, { + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var loader = new FileLoader( this.manager ); + loader.load( url, function ( text ) { + + var json; + + try { + + json = JSON.parse( text ); + + } catch ( e ) { + + console.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' ); + json = JSON.parse( text.substring( 65, text.length - 2 ) ); + + } + + var font = scope.parse( json ); + + if ( onLoad ) onLoad( font ); + + }, onProgress, onError ); + + }, + + parse: function ( json ) { + + return new Font( json ); + + } + +} ); + +var context; + +var AudioContext = { + + getContext: function () { + + if ( context === undefined ) { + + context = new ( window.AudioContext || window.webkitAudioContext )(); + + } + + return context; + + }, + + setContext: function ( value ) { + + context = value; + + } + +}; + +/** + * @author Reece Aaron Lecrivain / http://reecenotes.com/ + */ + +function AudioLoader( manager ) { + + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + +} + +Object.assign( AudioLoader.prototype, { + + load: function ( url, onLoad, onProgress, onError ) { + + var loader = new FileLoader( this.manager ); + loader.setResponseType( 'arraybuffer' ); + loader.load( url, function ( buffer ) { + + var context = AudioContext.getContext(); + + context.decodeAudioData( buffer, function ( audioBuffer ) { + + onLoad( audioBuffer ); + + } ); + + }, onProgress, onError ); + + } + +} ); + +/** + * @author abelnation / http://github.com/abelnation + */ + +function RectAreaLight ( color, intensity, width, height ) { + + Light.call( this, color, intensity ); + + this.type = 'RectAreaLight'; + + this.position.set( 0, 1, 0 ); + this.updateMatrix(); + + this.width = ( width !== undefined ) ? width : 10; + this.height = ( height !== undefined ) ? height : 10; + + // TODO (abelnation): distance/decay + + // TODO (abelnation): update method for RectAreaLight to update transform to lookat target + + // TODO (abelnation): shadows + // this.shadow = new THREE.RectAreaLightShadow( new THREE.PerspectiveCamera( 90, 1, 0.5, 500 ) ); + +} + +// TODO (abelnation): RectAreaLight update when light shape is changed +RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), { + + constructor: RectAreaLight, + + isRectAreaLight: true, + + copy: function ( source ) { + + Light.prototype.copy.call( this, source ); + + this.width = source.width; + this.height = source.height; + + // this.shadow = source.shadow.clone(); + + return this; + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function StereoCamera() { + + this.type = 'StereoCamera'; + + this.aspect = 1; + + this.eyeSep = 0.064; + + this.cameraL = new PerspectiveCamera(); + this.cameraL.layers.enable( 1 ); + this.cameraL.matrixAutoUpdate = false; + + this.cameraR = new PerspectiveCamera(); + this.cameraR.layers.enable( 2 ); + this.cameraR.matrixAutoUpdate = false; + +} + +Object.assign( StereoCamera.prototype, { + + update: ( function () { + + var instance, focus, fov, aspect, near, far, zoom; + + var eyeRight = new Matrix4(); + var eyeLeft = new Matrix4(); + + return function update( camera ) { + + var needsUpdate = instance !== this || focus !== camera.focus || fov !== camera.fov || + aspect !== camera.aspect * this.aspect || near !== camera.near || + far !== camera.far || zoom !== camera.zoom; + + if ( needsUpdate ) { + + instance = this; + focus = camera.focus; + fov = camera.fov; + aspect = camera.aspect * this.aspect; + near = camera.near; + far = camera.far; + zoom = camera.zoom; + + // Off-axis stereoscopic effect based on + // http://paulbourke.net/stereographics/stereorender/ + + var projectionMatrix = camera.projectionMatrix.clone(); + var eyeSep = this.eyeSep / 2; + var eyeSepOnProjection = eyeSep * near / focus; + var ymax = ( near * Math.tan( _Math.DEG2RAD * fov * 0.5 ) ) / zoom; + var xmin, xmax; + + // translate xOffset + + eyeLeft.elements[ 12 ] = - eyeSep; + eyeRight.elements[ 12 ] = eyeSep; + + // for left eye + + xmin = - ymax * aspect + eyeSepOnProjection; + xmax = ymax * aspect + eyeSepOnProjection; + + projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin ); + projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); + + this.cameraL.projectionMatrix.copy( projectionMatrix ); + + // for right eye + + xmin = - ymax * aspect - eyeSepOnProjection; + xmax = ymax * aspect - eyeSepOnProjection; + + projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin ); + projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); + + this.cameraR.projectionMatrix.copy( projectionMatrix ); + + } + + this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( eyeLeft ); + this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( eyeRight ); + + }; + + } )() + +} ); + +/** + * Camera for rendering cube maps + * - renders scene into axis-aligned cube + * + * @author alteredq / http://alteredqualia.com/ + */ + +function CubeCamera( near, far, cubeResolution ) { + + Object3D.call( this ); + + this.type = 'CubeCamera'; + + var fov = 90, aspect = 1; + + var cameraPX = new PerspectiveCamera( fov, aspect, near, far ); + cameraPX.up.set( 0, - 1, 0 ); + cameraPX.lookAt( new Vector3( 1, 0, 0 ) ); + this.add( cameraPX ); + + var cameraNX = new PerspectiveCamera( fov, aspect, near, far ); + cameraNX.up.set( 0, - 1, 0 ); + cameraNX.lookAt( new Vector3( - 1, 0, 0 ) ); + this.add( cameraNX ); + + var cameraPY = new PerspectiveCamera( fov, aspect, near, far ); + cameraPY.up.set( 0, 0, 1 ); + cameraPY.lookAt( new Vector3( 0, 1, 0 ) ); + this.add( cameraPY ); + + var cameraNY = new PerspectiveCamera( fov, aspect, near, far ); + cameraNY.up.set( 0, 0, - 1 ); + cameraNY.lookAt( new Vector3( 0, - 1, 0 ) ); + this.add( cameraNY ); + + var cameraPZ = new PerspectiveCamera( fov, aspect, near, far ); + cameraPZ.up.set( 0, - 1, 0 ); + cameraPZ.lookAt( new Vector3( 0, 0, 1 ) ); + this.add( cameraPZ ); + + var cameraNZ = new PerspectiveCamera( fov, aspect, near, far ); + cameraNZ.up.set( 0, - 1, 0 ); + cameraNZ.lookAt( new Vector3( 0, 0, - 1 ) ); + this.add( cameraNZ ); + + var options = { format: RGBFormat, magFilter: LinearFilter, minFilter: LinearFilter }; + + this.renderTarget = new WebGLRenderTargetCube( cubeResolution, cubeResolution, options ); + + this.updateCubeMap = function ( renderer, scene ) { + + if ( this.parent === null ) this.updateMatrixWorld(); + + var renderTarget = this.renderTarget; + var generateMipmaps = renderTarget.texture.generateMipmaps; + + renderTarget.texture.generateMipmaps = false; + + renderTarget.activeCubeFace = 0; + renderer.render( scene, cameraPX, renderTarget ); + + renderTarget.activeCubeFace = 1; + renderer.render( scene, cameraNX, renderTarget ); + + renderTarget.activeCubeFace = 2; + renderer.render( scene, cameraPY, renderTarget ); + + renderTarget.activeCubeFace = 3; + renderer.render( scene, cameraNY, renderTarget ); + + renderTarget.activeCubeFace = 4; + renderer.render( scene, cameraPZ, renderTarget ); + + renderTarget.texture.generateMipmaps = generateMipmaps; + + renderTarget.activeCubeFace = 5; + renderer.render( scene, cameraNZ, renderTarget ); + + renderer.setRenderTarget( null ); + + }; + +} + +CubeCamera.prototype = Object.create( Object3D.prototype ); +CubeCamera.prototype.constructor = CubeCamera; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function AudioListener() { + + Object3D.call( this ); + + this.type = 'AudioListener'; + + this.context = AudioContext.getContext(); + + this.gain = this.context.createGain(); + this.gain.connect( this.context.destination ); + + this.filter = null; + +} + +AudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), { + + constructor: AudioListener, + + getInput: function () { + + return this.gain; + + }, + + removeFilter: function ( ) { + + if ( this.filter !== null ) { + + this.gain.disconnect( this.filter ); + this.filter.disconnect( this.context.destination ); + this.gain.connect( this.context.destination ); + this.filter = null; + + } + + }, + + getFilter: function () { + + return this.filter; + + }, + + setFilter: function ( value ) { + + if ( this.filter !== null ) { + + this.gain.disconnect( this.filter ); + this.filter.disconnect( this.context.destination ); + + } else { + + this.gain.disconnect( this.context.destination ); + + } + + this.filter = value; + this.gain.connect( this.filter ); + this.filter.connect( this.context.destination ); + + }, + + getMasterVolume: function () { + + return this.gain.gain.value; + + }, + + setMasterVolume: function ( value ) { + + this.gain.gain.value = value; + + }, + + updateMatrixWorld: ( function () { + + var position = new Vector3(); + var quaternion = new Quaternion(); + var scale = new Vector3(); + + var orientation = new Vector3(); + + return function updateMatrixWorld( force ) { + + Object3D.prototype.updateMatrixWorld.call( this, force ); + + var listener = this.context.listener; + var up = this.up; + + this.matrixWorld.decompose( position, quaternion, scale ); + + orientation.set( 0, 0, - 1 ).applyQuaternion( quaternion ); + + if ( listener.positionX ) { + + listener.positionX.setValueAtTime( position.x, this.context.currentTime ); + listener.positionY.setValueAtTime( position.y, this.context.currentTime ); + listener.positionZ.setValueAtTime( position.z, this.context.currentTime ); + listener.forwardX.setValueAtTime( orientation.x, this.context.currentTime ); + listener.forwardY.setValueAtTime( orientation.y, this.context.currentTime ); + listener.forwardZ.setValueAtTime( orientation.z, this.context.currentTime ); + listener.upX.setValueAtTime( up.x, this.context.currentTime ); + listener.upY.setValueAtTime( up.y, this.context.currentTime ); + listener.upZ.setValueAtTime( up.z, this.context.currentTime ); + + } else { + + listener.setPosition( position.x, position.y, position.z ); + listener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z ); + + } + + }; + + } )() + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + * @author Reece Aaron Lecrivain / http://reecenotes.com/ + */ + +function Audio( listener ) { + + Object3D.call( this ); + + this.type = 'Audio'; + + this.context = listener.context; + + this.gain = this.context.createGain(); + this.gain.connect( listener.getInput() ); + + this.autoplay = false; + + this.buffer = null; + this.loop = false; + this.startTime = 0; + this.playbackRate = 1; + this.isPlaying = false; + this.hasPlaybackControl = true; + this.sourceType = 'empty'; + + this.filters = []; + +} + +Audio.prototype = Object.assign( Object.create( Object3D.prototype ), { + + constructor: Audio, + + getOutput: function () { + + return this.gain; + + }, + + setNodeSource: function ( audioNode ) { + + this.hasPlaybackControl = false; + this.sourceType = 'audioNode'; + this.source = audioNode; + this.connect(); + + return this; + + }, + + setBuffer: function ( audioBuffer ) { + + this.buffer = audioBuffer; + this.sourceType = 'buffer'; + + if ( this.autoplay ) this.play(); + + return this; + + }, + + play: function () { + + if ( this.isPlaying === true ) { + + console.warn( 'THREE.Audio: Audio is already playing.' ); + return; + + } + + if ( this.hasPlaybackControl === false ) { + + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; + + } + + var source = this.context.createBufferSource(); + + source.buffer = this.buffer; + source.loop = this.loop; + source.onended = this.onEnded.bind( this ); + source.playbackRate.setValueAtTime( this.playbackRate, this.startTime ); + source.start( 0, this.startTime ); + + this.isPlaying = true; + + this.source = source; + + return this.connect(); + + }, + + pause: function () { + + if ( this.hasPlaybackControl === false ) { + + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; + + } + + this.source.stop(); + this.startTime = this.context.currentTime; + this.isPlaying = false; + + return this; + + }, + + stop: function () { + + if ( this.hasPlaybackControl === false ) { + + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; + + } + + this.source.stop(); + this.startTime = 0; + this.isPlaying = false; + + return this; + + }, + + connect: function () { + + if ( this.filters.length > 0 ) { + + this.source.connect( this.filters[ 0 ] ); + + for ( var i = 1, l = this.filters.length; i < l; i ++ ) { + + this.filters[ i - 1 ].connect( this.filters[ i ] ); + + } + + this.filters[ this.filters.length - 1 ].connect( this.getOutput() ); + + } else { + + this.source.connect( this.getOutput() ); + + } + + return this; + + }, + + disconnect: function () { + + if ( this.filters.length > 0 ) { + + this.source.disconnect( this.filters[ 0 ] ); + + for ( var i = 1, l = this.filters.length; i < l; i ++ ) { + + this.filters[ i - 1 ].disconnect( this.filters[ i ] ); + + } + + this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() ); + + } else { + + this.source.disconnect( this.getOutput() ); + + } + + return this; + + }, + + getFilters: function () { + + return this.filters; + + }, + + setFilters: function ( value ) { + + if ( ! value ) value = []; + + if ( this.isPlaying === true ) { + + this.disconnect(); + this.filters = value; + this.connect(); + + } else { + + this.filters = value; + + } + + return this; + + }, + + getFilter: function () { + + return this.getFilters()[ 0 ]; + + }, + + setFilter: function ( filter ) { + + return this.setFilters( filter ? [ filter ] : [] ); + + }, + + setPlaybackRate: function ( value ) { + + if ( this.hasPlaybackControl === false ) { + + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; + + } + + this.playbackRate = value; + + if ( this.isPlaying === true ) { + + this.source.playbackRate.setValueAtTime( this.playbackRate, this.context.currentTime ); + + } + + return this; + + }, + + getPlaybackRate: function () { + + return this.playbackRate; + + }, + + onEnded: function () { + + this.isPlaying = false; + + }, + + getLoop: function () { + + if ( this.hasPlaybackControl === false ) { + + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return false; + + } + + return this.loop; + + }, + + setLoop: function ( value ) { + + if ( this.hasPlaybackControl === false ) { + + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; + + } + + this.loop = value; + + if ( this.isPlaying === true ) { + + this.source.loop = this.loop; + + } + + return this; + + }, + + getVolume: function () { + + return this.gain.gain.value; + + }, + + + setVolume: function ( value ) { + + this.gain.gain.value = value; + + return this; + + } + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function PositionalAudio( listener ) { + + Audio.call( this, listener ); + + this.panner = this.context.createPanner(); + this.panner.connect( this.gain ); + +} + +PositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), { + + constructor: PositionalAudio, + + getOutput: function () { + + return this.panner; + + }, + + getRefDistance: function () { + + return this.panner.refDistance; + + }, + + setRefDistance: function ( value ) { + + this.panner.refDistance = value; + + }, + + getRolloffFactor: function () { + + return this.panner.rolloffFactor; + + }, + + setRolloffFactor: function ( value ) { + + this.panner.rolloffFactor = value; + + }, + + getDistanceModel: function () { + + return this.panner.distanceModel; + + }, + + setDistanceModel: function ( value ) { + + this.panner.distanceModel = value; + + }, + + getMaxDistance: function () { + + return this.panner.maxDistance; + + }, + + setMaxDistance: function ( value ) { + + this.panner.maxDistance = value; + + }, + + updateMatrixWorld: ( function () { + + var position = new Vector3(); + + return function updateMatrixWorld( force ) { + + Object3D.prototype.updateMatrixWorld.call( this, force ); + + position.setFromMatrixPosition( this.matrixWorld ); + + this.panner.setPosition( position.x, position.y, position.z ); + + }; + + } )() + + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function AudioAnalyser( audio, fftSize ) { + + this.analyser = audio.context.createAnalyser(); + this.analyser.fftSize = fftSize !== undefined ? fftSize : 2048; + + this.data = new Uint8Array( this.analyser.frequencyBinCount ); + + audio.getOutput().connect( this.analyser ); + +} + +Object.assign( AudioAnalyser.prototype, { + + getFrequencyData: function () { + + this.analyser.getByteFrequencyData( this.data ); + + return this.data; + + }, + + getAverageFrequency: function () { + + var value = 0, data = this.getFrequencyData(); + + for ( var i = 0; i < data.length; i ++ ) { + + value += data[ i ]; + + } + + return value / data.length; + + } + +} ); + +/** + * + * Buffered scene graph property that allows weighted accumulation. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ + +function PropertyMixer( binding, typeName, valueSize ) { + + this.binding = binding; + this.valueSize = valueSize; + + var bufferType = Float64Array, + mixFunction; + + switch ( typeName ) { + + case 'quaternion': + mixFunction = this._slerp; + break; + + case 'string': + case 'bool': + bufferType = Array; + mixFunction = this._select; + break; + + default: + mixFunction = this._lerp; + + } + + this.buffer = new bufferType( valueSize * 4 ); + // layout: [ incoming | accu0 | accu1 | orig ] + // + // interpolators can use .buffer as their .result + // the data then goes to 'incoming' + // + // 'accu0' and 'accu1' are used frame-interleaved for + // the cumulative result and are compared to detect + // changes + // + // 'orig' stores the original state of the property + + this._mixBufferRegion = mixFunction; + + this.cumulativeWeight = 0; + + this.useCount = 0; + this.referenceCount = 0; + +} + +PropertyMixer.prototype = { + + constructor: PropertyMixer, + + // accumulate data in the 'incoming' region into 'accu' + accumulate: function( accuIndex, weight ) { + + // note: happily accumulating nothing when weight = 0, the caller knows + // the weight and shouldn't have made the call in the first place + + var buffer = this.buffer, + stride = this.valueSize, + offset = accuIndex * stride + stride, + + currentWeight = this.cumulativeWeight; + + if ( currentWeight === 0 ) { + + // accuN := incoming * weight + + for ( var i = 0; i !== stride; ++ i ) { + + buffer[ offset + i ] = buffer[ i ]; + + } + + currentWeight = weight; + + } else { + + // accuN := accuN + incoming * weight + + currentWeight += weight; + var mix = weight / currentWeight; + this._mixBufferRegion( buffer, offset, 0, mix, stride ); + + } + + this.cumulativeWeight = currentWeight; + + }, + + // apply the state of 'accu' to the binding when accus differ + apply: function( accuIndex ) { + + var stride = this.valueSize, + buffer = this.buffer, + offset = accuIndex * stride + stride, + + weight = this.cumulativeWeight, + + binding = this.binding; + + this.cumulativeWeight = 0; + + if ( weight < 1 ) { + + // accuN := accuN + original * ( 1 - cumulativeWeight ) + + var originalValueOffset = stride * 3; + + this._mixBufferRegion( + buffer, offset, originalValueOffset, 1 - weight, stride ); + + } + + for ( var i = stride, e = stride + stride; i !== e; ++ i ) { + + if ( buffer[ i ] !== buffer[ i + stride ] ) { + + // value has changed -> update scene graph + + binding.setValue( buffer, offset ); + break; + + } + + } + + }, + + // remember the state of the bound property and copy it to both accus + saveOriginalState: function() { + + var binding = this.binding; + + var buffer = this.buffer, + stride = this.valueSize, + + originalValueOffset = stride * 3; + + binding.getValue( buffer, originalValueOffset ); + + // accu[0..1] := orig -- initially detect changes against the original + for ( var i = stride, e = originalValueOffset; i !== e; ++ i ) { + + buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; + + } + + this.cumulativeWeight = 0; + + }, + + // apply the state previously taken via 'saveOriginalState' to the binding + restoreOriginalState: function() { + + var originalValueOffset = this.valueSize * 3; + this.binding.setValue( this.buffer, originalValueOffset ); + + }, + + + // mix functions + + _select: function( buffer, dstOffset, srcOffset, t, stride ) { + + if ( t >= 0.5 ) { + + for ( var i = 0; i !== stride; ++ i ) { + + buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; + + } + + } + + }, + + _slerp: function( buffer, dstOffset, srcOffset, t, stride ) { + + Quaternion.slerpFlat( buffer, dstOffset, + buffer, dstOffset, buffer, srcOffset, t ); + + }, + + _lerp: function( buffer, dstOffset, srcOffset, t, stride ) { + + var s = 1 - t; + + for ( var i = 0; i !== stride; ++ i ) { + + var j = dstOffset + i; + + buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; + + } + + } + +}; + +/** + * + * A reference to a real property in the scene graph. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ + +function PropertyBinding( rootNode, path, parsedPath ) { + + this.path = path; + this.parsedPath = parsedPath || + PropertyBinding.parseTrackName( path ); + + this.node = PropertyBinding.findNode( + rootNode, this.parsedPath.nodeName ) || rootNode; + + this.rootNode = rootNode; + +} + +PropertyBinding.prototype = { + + constructor: PropertyBinding, + + getValue: function getValue_unbound( targetArray, offset ) { + + this.bind(); + this.getValue( targetArray, offset ); + + // Note: This class uses a State pattern on a per-method basis: + // 'bind' sets 'this.getValue' / 'setValue' and shadows the + // prototype version of these methods with one that represents + // the bound state. When the property is not found, the methods + // become no-ops. + + }, + + setValue: function getValue_unbound( sourceArray, offset ) { + + this.bind(); + this.setValue( sourceArray, offset ); + + }, + + // create getter / setter pair for a property in the scene graph + bind: function() { + + var targetObject = this.node, + parsedPath = this.parsedPath, + + objectName = parsedPath.objectName, + propertyName = parsedPath.propertyName, + propertyIndex = parsedPath.propertyIndex; + + if ( ! targetObject ) { + + targetObject = PropertyBinding.findNode( + this.rootNode, parsedPath.nodeName ) || this.rootNode; + + this.node = targetObject; + + } + + // set fail state so we can just 'return' on error + this.getValue = this._getValue_unavailable; + this.setValue = this._setValue_unavailable; + + // ensure there is a value node + if ( ! targetObject ) { + + console.error( " trying to update node for track: " + this.path + " but it wasn't found." ); + return; + + } + + if ( objectName ) { + + var objectIndex = parsedPath.objectIndex; + + // special cases were we need to reach deeper into the hierarchy to get the face materials.... + switch ( objectName ) { + + case 'materials': + + if ( ! targetObject.material ) { + + console.error( ' can not bind to material as node does not have a material', this ); + return; + + } + + if ( ! targetObject.material.materials ) { + + console.error( ' can not bind to material.materials as node.material does not have a materials array', this ); + return; + + } + + targetObject = targetObject.material.materials; + + break; + + case 'bones': + + if ( ! targetObject.skeleton ) { + + console.error( ' can not bind to bones as node does not have a skeleton', this ); + return; + + } + + // potential future optimization: skip this if propertyIndex is already an integer + // and convert the integer string to a true integer. + + targetObject = targetObject.skeleton.bones; + + // support resolving morphTarget names into indices. + for ( var i = 0; i < targetObject.length; i ++ ) { + + if ( targetObject[ i ].name === objectIndex ) { + + objectIndex = i; + break; + + } + + } + + break; + + default: + + if ( targetObject[ objectName ] === undefined ) { + + console.error( ' can not bind to objectName of node, undefined', this ); + return; + + } + + targetObject = targetObject[ objectName ]; + + } + + + if ( objectIndex !== undefined ) { + + if ( targetObject[ objectIndex ] === undefined ) { + + console.error( " trying to bind to objectIndex of objectName, but is undefined:", this, targetObject ); + return; + + } + + targetObject = targetObject[ objectIndex ]; + + } + + } + + // resolve property + var nodeProperty = targetObject[ propertyName ]; + + if ( nodeProperty === undefined ) { + + var nodeName = parsedPath.nodeName; + + console.error( " trying to update property for track: " + nodeName + + '.' + propertyName + " but it wasn't found.", targetObject ); + return; + + } + + // determine versioning scheme + var versioning = this.Versioning.None; + + if ( targetObject.needsUpdate !== undefined ) { // material + + versioning = this.Versioning.NeedsUpdate; + this.targetObject = targetObject; + + } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform + + versioning = this.Versioning.MatrixWorldNeedsUpdate; + this.targetObject = targetObject; + + } + + // determine how the property gets bound + var bindingType = this.BindingType.Direct; + + if ( propertyIndex !== undefined ) { + // access a sub element of the property array (only primitives are supported right now) + + if ( propertyName === "morphTargetInfluences" ) { + // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. + + // support resolving morphTarget names into indices. + if ( ! targetObject.geometry ) { + + console.error( ' can not bind to morphTargetInfluences becasuse node does not have a geometry', this ); + return; + + } + + if ( ! targetObject.geometry.morphTargets ) { + + console.error( ' can not bind to morphTargetInfluences becasuse node does not have a geometry.morphTargets', this ); + return; + + } + + for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) { + + if ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) { + + propertyIndex = i; + break; + + } + + } + + } + + bindingType = this.BindingType.ArrayElement; + + this.resolvedProperty = nodeProperty; + this.propertyIndex = propertyIndex; + + } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { + // must use copy for Object3D.Euler/Quaternion + + bindingType = this.BindingType.HasFromToArray; + + this.resolvedProperty = nodeProperty; + + } else if ( nodeProperty.length !== undefined ) { + + bindingType = this.BindingType.EntireArray; + + this.resolvedProperty = nodeProperty; + + } else { + + this.propertyName = propertyName; + + } + + // select getter / setter + this.getValue = this.GetterByBindingType[ bindingType ]; + this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; + + }, + + unbind: function() { + + this.node = null; + + // back to the prototype version of getValue / setValue + // note: avoiding to mutate the shape of 'this' via 'delete' + this.getValue = this._getValue_unbound; + this.setValue = this._setValue_unbound; + + } + +}; + +Object.assign( PropertyBinding.prototype, { // prototype, continued + + // these are used to "bind" a nonexistent property + _getValue_unavailable: function() {}, + _setValue_unavailable: function() {}, + + // initial state of these methods that calls 'bind' + _getValue_unbound: PropertyBinding.prototype.getValue, + _setValue_unbound: PropertyBinding.prototype.setValue, + + BindingType: { + Direct: 0, + EntireArray: 1, + ArrayElement: 2, + HasFromToArray: 3 + }, + + Versioning: { + None: 0, + NeedsUpdate: 1, + MatrixWorldNeedsUpdate: 2 + }, + + GetterByBindingType: [ + + function getValue_direct( buffer, offset ) { + + buffer[ offset ] = this.node[ this.propertyName ]; + + }, + + function getValue_array( buffer, offset ) { + + var source = this.resolvedProperty; + + for ( var i = 0, n = source.length; i !== n; ++ i ) { + + buffer[ offset ++ ] = source[ i ]; + + } + + }, + + function getValue_arrayElement( buffer, offset ) { + + buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ]; + + }, + + function getValue_toArray( buffer, offset ) { + + this.resolvedProperty.toArray( buffer, offset ); + + } + + ], + + SetterByBindingTypeAndVersioning: [ + + [ + // Direct + + function setValue_direct( buffer, offset ) { + + this.node[ this.propertyName ] = buffer[ offset ]; + + }, + + function setValue_direct_setNeedsUpdate( buffer, offset ) { + + this.node[ this.propertyName ] = buffer[ offset ]; + this.targetObject.needsUpdate = true; + + }, + + function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) { + + this.node[ this.propertyName ] = buffer[ offset ]; + this.targetObject.matrixWorldNeedsUpdate = true; + + } + + ], [ + + // EntireArray + + function setValue_array( buffer, offset ) { + + var dest = this.resolvedProperty; + + for ( var i = 0, n = dest.length; i !== n; ++ i ) { + + dest[ i ] = buffer[ offset ++ ]; + + } + + }, + + function setValue_array_setNeedsUpdate( buffer, offset ) { + + var dest = this.resolvedProperty; + + for ( var i = 0, n = dest.length; i !== n; ++ i ) { + + dest[ i ] = buffer[ offset ++ ]; + + } + + this.targetObject.needsUpdate = true; + + }, + + function setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) { + + var dest = this.resolvedProperty; + + for ( var i = 0, n = dest.length; i !== n; ++ i ) { + + dest[ i ] = buffer[ offset ++ ]; + + } + + this.targetObject.matrixWorldNeedsUpdate = true; + + } + + ], [ + + // ArrayElement + + function setValue_arrayElement( buffer, offset ) { + + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + + }, + + function setValue_arrayElement_setNeedsUpdate( buffer, offset ) { + + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + this.targetObject.needsUpdate = true; + + }, + + function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) { + + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + this.targetObject.matrixWorldNeedsUpdate = true; + + } + + ], [ + + // HasToFromArray + + function setValue_fromArray( buffer, offset ) { + + this.resolvedProperty.fromArray( buffer, offset ); + + }, + + function setValue_fromArray_setNeedsUpdate( buffer, offset ) { + + this.resolvedProperty.fromArray( buffer, offset ); + this.targetObject.needsUpdate = true; + + }, + + function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) { + + this.resolvedProperty.fromArray( buffer, offset ); + this.targetObject.matrixWorldNeedsUpdate = true; + + } + + ] + + ] + +} ); + +PropertyBinding.Composite = + function( targetGroup, path, optionalParsedPath ) { + + var parsedPath = optionalParsedPath || + PropertyBinding.parseTrackName( path ); + + this._targetGroup = targetGroup; + this._bindings = targetGroup.subscribe_( path, parsedPath ); + +}; + +PropertyBinding.Composite.prototype = { + + constructor: PropertyBinding.Composite, + + getValue: function( array, offset ) { + + this.bind(); // bind all binding + + var firstValidIndex = this._targetGroup.nCachedObjects_, + binding = this._bindings[ firstValidIndex ]; + + // and only call .getValue on the first + if ( binding !== undefined ) binding.getValue( array, offset ); + + }, + + setValue: function( array, offset ) { + + var bindings = this._bindings; + + for ( var i = this._targetGroup.nCachedObjects_, + n = bindings.length; i !== n; ++ i ) { + + bindings[ i ].setValue( array, offset ); + + } + + }, + + bind: function() { + + var bindings = this._bindings; + + for ( var i = this._targetGroup.nCachedObjects_, + n = bindings.length; i !== n; ++ i ) { + + bindings[ i ].bind(); + + } + + }, + + unbind: function() { + + var bindings = this._bindings; + + for ( var i = this._targetGroup.nCachedObjects_, + n = bindings.length; i !== n; ++ i ) { + + bindings[ i ].unbind(); + + } + + } + +}; + +PropertyBinding.create = function( root, path, parsedPath ) { + + if ( ! ( root && root.isAnimationObjectGroup ) ) { + + return new PropertyBinding( root, path, parsedPath ); + + } else { + + return new PropertyBinding.Composite( root, path, parsedPath ); + + } + +}; + +PropertyBinding.parseTrackName = function( trackName ) { + + // matches strings in the form of: + // nodeName.property + // nodeName.property[accessor] + // nodeName.material.property[accessor] + // uuid.property[accessor] + // uuid.objectName[objectIndex].propertyName[propertyIndex] + // parentName/nodeName.property + // parentName/parentName/nodeName.property[index] + // .bone[Armature.DEF_cog].position + // scene:helium_balloon_model:helium_balloon_model.position + // created and tested via https://regex101.com/#javascript + + var re = /^((?:[\w-]+[\/:])*)([\w-]+)?(?:\.([\w-]+)(?:\[(.+)\])?)?\.([\w-]+)(?:\[(.+)\])?$/; + var matches = re.exec( trackName ); + + if ( ! matches ) { + + throw new Error( "cannot parse trackName at all: " + trackName ); + + } + + var results = { + // directoryName: matches[ 1 ], // (tschw) currently unused + nodeName: matches[ 2 ], // allowed to be null, specified root node. + objectName: matches[ 3 ], + objectIndex: matches[ 4 ], + propertyName: matches[ 5 ], + propertyIndex: matches[ 6 ] // allowed to be null, specifies that the whole property is set. + }; + + if ( results.propertyName === null || results.propertyName.length === 0 ) { + + throw new Error( "can not parse propertyName from trackName: " + trackName ); + + } + + return results; + +}; + +PropertyBinding.findNode = function( root, nodeName ) { + + if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === -1 || nodeName === root.name || nodeName === root.uuid ) { + + return root; + + } + + // search into skeleton bones. + if ( root.skeleton ) { + + var searchSkeleton = function( skeleton ) { + + for( var i = 0; i < skeleton.bones.length; i ++ ) { + + var bone = skeleton.bones[ i ]; + + if ( bone.name === nodeName ) { + + return bone; + + } + } + + return null; + + }; + + var bone = searchSkeleton( root.skeleton ); + + if ( bone ) { + + return bone; + + } + } + + // search into node subtree. + if ( root.children ) { + + var searchNodeSubtree = function( children ) { + + for( var i = 0; i < children.length; i ++ ) { + + var childNode = children[ i ]; + + if ( childNode.name === nodeName || childNode.uuid === nodeName ) { + + return childNode; + + } + + var result = searchNodeSubtree( childNode.children ); + + if ( result ) return result; + + } + + return null; + + }; + + var subTreeNode = searchNodeSubtree( root.children ); + + if ( subTreeNode ) { + + return subTreeNode; + + } + + } + + return null; + +}; + +/** + * + * A group of objects that receives a shared animation state. + * + * Usage: + * + * - Add objects you would otherwise pass as 'root' to the + * constructor or the .clipAction method of AnimationMixer. + * + * - Instead pass this object as 'root'. + * + * - You can also add and remove objects later when the mixer + * is running. + * + * Note: + * + * Objects of this class appear as one object to the mixer, + * so cache control of the individual objects must be done + * on the group. + * + * Limitation: + * + * - The animated properties must be compatible among the + * all objects in the group. + * + * - A single property can either be controlled through a + * target group or directly, but not both. + * + * @author tschw + */ + +function AnimationObjectGroup( var_args ) { + + this.uuid = _Math.generateUUID(); + + // cached objects followed by the active ones + this._objects = Array.prototype.slice.call( arguments ); + + this.nCachedObjects_ = 0; // threshold + // note: read by PropertyBinding.Composite + + var indices = {}; + this._indicesByUUID = indices; // for bookkeeping + + for ( var i = 0, n = arguments.length; i !== n; ++ i ) { + + indices[ arguments[ i ].uuid ] = i; + + } + + this._paths = []; // inside: string + this._parsedPaths = []; // inside: { we don't care, here } + this._bindings = []; // inside: Array< PropertyBinding > + this._bindingsIndicesByPath = {}; // inside: indices in these arrays + + var scope = this; + + this.stats = { + + objects: { + get total() { return scope._objects.length; }, + get inUse() { return this.total - scope.nCachedObjects_; } + }, + + get bindingsPerObject() { return scope._bindings.length; } + + }; + +} + +AnimationObjectGroup.prototype = { + + constructor: AnimationObjectGroup, + + isAnimationObjectGroup: true, + + add: function( var_args ) { + + var objects = this._objects, + nObjects = objects.length, + nCachedObjects = this.nCachedObjects_, + indicesByUUID = this._indicesByUUID, + paths = this._paths, + parsedPaths = this._parsedPaths, + bindings = this._bindings, + nBindings = bindings.length; + + for ( var i = 0, n = arguments.length; i !== n; ++ i ) { + + var object = arguments[ i ], + uuid = object.uuid, + index = indicesByUUID[ uuid ], + knownObject = undefined; + + if ( index === undefined ) { + + // unknown object -> add it to the ACTIVE region + + index = nObjects ++; + indicesByUUID[ uuid ] = index; + objects.push( object ); + + // accounting is done, now do the same for all bindings + + for ( var j = 0, m = nBindings; j !== m; ++ j ) { + + bindings[ j ].push( + new PropertyBinding( + object, paths[ j ], parsedPaths[ j ] ) ); + + } + + } else if ( index < nCachedObjects ) { + + knownObject = objects[ index ]; + + // move existing object to the ACTIVE region + + var firstActiveIndex = -- nCachedObjects, + lastCachedObject = objects[ firstActiveIndex ]; + + indicesByUUID[ lastCachedObject.uuid ] = index; + objects[ index ] = lastCachedObject; + + indicesByUUID[ uuid ] = firstActiveIndex; + objects[ firstActiveIndex ] = object; + + // accounting is done, now do the same for all bindings + + for ( var j = 0, m = nBindings; j !== m; ++ j ) { + + var bindingsForPath = bindings[ j ], + lastCached = bindingsForPath[ firstActiveIndex ], + binding = bindingsForPath[ index ]; + + bindingsForPath[ index ] = lastCached; + + if ( binding === undefined ) { + + // since we do not bother to create new bindings + // for objects that are cached, the binding may + // or may not exist + + binding = new PropertyBinding( + object, paths[ j ], parsedPaths[ j ] ); + + } + + bindingsForPath[ firstActiveIndex ] = binding; + + } + + } else if ( objects[ index ] !== knownObject) { + + console.error( "Different objects with the same UUID " + + "detected. Clean the caches or recreate your " + + "infrastructure when reloading scenes..." ); + + } // else the object is already where we want it to be + + } // for arguments + + this.nCachedObjects_ = nCachedObjects; + + }, + + remove: function( var_args ) { + + var objects = this._objects, + nCachedObjects = this.nCachedObjects_, + indicesByUUID = this._indicesByUUID, + bindings = this._bindings, + nBindings = bindings.length; + + for ( var i = 0, n = arguments.length; i !== n; ++ i ) { + + var object = arguments[ i ], + uuid = object.uuid, + index = indicesByUUID[ uuid ]; + + if ( index !== undefined && index >= nCachedObjects ) { + + // move existing object into the CACHED region + + var lastCachedIndex = nCachedObjects ++, + firstActiveObject = objects[ lastCachedIndex ]; + + indicesByUUID[ firstActiveObject.uuid ] = index; + objects[ index ] = firstActiveObject; + + indicesByUUID[ uuid ] = lastCachedIndex; + objects[ lastCachedIndex ] = object; + + // accounting is done, now do the same for all bindings + + for ( var j = 0, m = nBindings; j !== m; ++ j ) { + + var bindingsForPath = bindings[ j ], + firstActive = bindingsForPath[ lastCachedIndex ], + binding = bindingsForPath[ index ]; + + bindingsForPath[ index ] = firstActive; + bindingsForPath[ lastCachedIndex ] = binding; + + } + + } + + } // for arguments + + this.nCachedObjects_ = nCachedObjects; + + }, + + // remove & forget + uncache: function( var_args ) { + + var objects = this._objects, + nObjects = objects.length, + nCachedObjects = this.nCachedObjects_, + indicesByUUID = this._indicesByUUID, + bindings = this._bindings, + nBindings = bindings.length; + + for ( var i = 0, n = arguments.length; i !== n; ++ i ) { + + var object = arguments[ i ], + uuid = object.uuid, + index = indicesByUUID[ uuid ]; + + if ( index !== undefined ) { + + delete indicesByUUID[ uuid ]; + + if ( index < nCachedObjects ) { + + // object is cached, shrink the CACHED region + + var firstActiveIndex = -- nCachedObjects, + lastCachedObject = objects[ firstActiveIndex ], + lastIndex = -- nObjects, + lastObject = objects[ lastIndex ]; + + // last cached object takes this object's place + indicesByUUID[ lastCachedObject.uuid ] = index; + objects[ index ] = lastCachedObject; + + // last object goes to the activated slot and pop + indicesByUUID[ lastObject.uuid ] = firstActiveIndex; + objects[ firstActiveIndex ] = lastObject; + objects.pop(); + + // accounting is done, now do the same for all bindings + + for ( var j = 0, m = nBindings; j !== m; ++ j ) { + + var bindingsForPath = bindings[ j ], + lastCached = bindingsForPath[ firstActiveIndex ], + last = bindingsForPath[ lastIndex ]; + + bindingsForPath[ index ] = lastCached; + bindingsForPath[ firstActiveIndex ] = last; + bindingsForPath.pop(); + + } + + } else { + + // object is active, just swap with the last and pop + + var lastIndex = -- nObjects, + lastObject = objects[ lastIndex ]; + + indicesByUUID[ lastObject.uuid ] = index; + objects[ index ] = lastObject; + objects.pop(); + + // accounting is done, now do the same for all bindings + + for ( var j = 0, m = nBindings; j !== m; ++ j ) { + + var bindingsForPath = bindings[ j ]; + + bindingsForPath[ index ] = bindingsForPath[ lastIndex ]; + bindingsForPath.pop(); + + } + + } // cached or active + + } // if object is known + + } // for arguments + + this.nCachedObjects_ = nCachedObjects; + + }, + + // Internal interface used by befriended PropertyBinding.Composite: + + subscribe_: function( path, parsedPath ) { + // returns an array of bindings for the given path that is changed + // according to the contained objects in the group + + var indicesByPath = this._bindingsIndicesByPath, + index = indicesByPath[ path ], + bindings = this._bindings; + + if ( index !== undefined ) return bindings[ index ]; + + var paths = this._paths, + parsedPaths = this._parsedPaths, + objects = this._objects, + nObjects = objects.length, + nCachedObjects = this.nCachedObjects_, + bindingsForPath = new Array( nObjects ); + + index = bindings.length; + + indicesByPath[ path ] = index; + + paths.push( path ); + parsedPaths.push( parsedPath ); + bindings.push( bindingsForPath ); + + for ( var i = nCachedObjects, + n = objects.length; i !== n; ++ i ) { + + var object = objects[ i ]; + + bindingsForPath[ i ] = + new PropertyBinding( object, path, parsedPath ); + + } + + return bindingsForPath; + + }, + + unsubscribe_: function( path ) { + // tells the group to forget about a property path and no longer + // update the array previously obtained with 'subscribe_' + + var indicesByPath = this._bindingsIndicesByPath, + index = indicesByPath[ path ]; + + if ( index !== undefined ) { + + var paths = this._paths, + parsedPaths = this._parsedPaths, + bindings = this._bindings, + lastBindingsIndex = bindings.length - 1, + lastBindings = bindings[ lastBindingsIndex ], + lastBindingsPath = path[ lastBindingsIndex ]; + + indicesByPath[ lastBindingsPath ] = index; + + bindings[ index ] = lastBindings; + bindings.pop(); + + parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ]; + parsedPaths.pop(); + + paths[ index ] = paths[ lastBindingsIndex ]; + paths.pop(); + + } + + } + +}; + +/** + * + * Action provided by AnimationMixer for scheduling clip playback on specific + * objects. + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + * + */ + +function AnimationAction( mixer, clip, localRoot ) { + + this._mixer = mixer; + this._clip = clip; + this._localRoot = localRoot || null; + + var tracks = clip.tracks, + nTracks = tracks.length, + interpolants = new Array( nTracks ); + + var interpolantSettings = { + endingStart: ZeroCurvatureEnding, + endingEnd: ZeroCurvatureEnding + }; + + for ( var i = 0; i !== nTracks; ++ i ) { + + var interpolant = tracks[ i ].createInterpolant( null ); + interpolants[ i ] = interpolant; + interpolant.settings = interpolantSettings; + + } + + this._interpolantSettings = interpolantSettings; + + this._interpolants = interpolants; // bound by the mixer + + // inside: PropertyMixer (managed by the mixer) + this._propertyBindings = new Array( nTracks ); + + this._cacheIndex = null; // for the memory manager + this._byClipCacheIndex = null; // for the memory manager + + this._timeScaleInterpolant = null; + this._weightInterpolant = null; + + this.loop = LoopRepeat; + this._loopCount = -1; + + // global mixer time when the action is to be started + // it's set back to 'null' upon start of the action + this._startTime = null; + + // scaled local time of the action + // gets clamped or wrapped to 0..clip.duration according to loop + this.time = 0; + + this.timeScale = 1; + this._effectiveTimeScale = 1; + + this.weight = 1; + this._effectiveWeight = 1; + + this.repetitions = Infinity; // no. of repetitions when looping + + this.paused = false; // false -> zero effective time scale + this.enabled = true; // true -> zero effective weight + + this.clampWhenFinished = false; // keep feeding the last frame? + + this.zeroSlopeAtStart = true; // for smooth interpolation w/o separate + this.zeroSlopeAtEnd = true; // clips for start, loop and end + +} + +AnimationAction.prototype = { + + constructor: AnimationAction, + + // State & Scheduling + + play: function() { + + this._mixer._activateAction( this ); + + return this; + + }, + + stop: function() { + + this._mixer._deactivateAction( this ); + + return this.reset(); + + }, + + reset: function() { + + this.paused = false; + this.enabled = true; + + this.time = 0; // restart clip + this._loopCount = -1; // forget previous loops + this._startTime = null; // forget scheduling + + return this.stopFading().stopWarping(); + + }, + + isRunning: function() { + + return this.enabled && ! this.paused && this.timeScale !== 0 && + this._startTime === null && this._mixer._isActiveAction( this ); + + }, + + // return true when play has been called + isScheduled: function() { + + return this._mixer._isActiveAction( this ); + + }, + + startAt: function( time ) { + + this._startTime = time; + + return this; + + }, + + setLoop: function( mode, repetitions ) { + + this.loop = mode; + this.repetitions = repetitions; + + return this; + + }, + + // Weight + + // set the weight stopping any scheduled fading + // although .enabled = false yields an effective weight of zero, this + // method does *not* change .enabled, because it would be confusing + setEffectiveWeight: function( weight ) { + + this.weight = weight; + + // note: same logic as when updated at runtime + this._effectiveWeight = this.enabled ? weight : 0; + + return this.stopFading(); + + }, + + // return the weight considering fading and .enabled + getEffectiveWeight: function() { + + return this._effectiveWeight; + + }, + + fadeIn: function( duration ) { + + return this._scheduleFading( duration, 0, 1 ); + + }, + + fadeOut: function( duration ) { + + return this._scheduleFading( duration, 1, 0 ); + + }, + + crossFadeFrom: function( fadeOutAction, duration, warp ) { + + fadeOutAction.fadeOut( duration ); + this.fadeIn( duration ); + + if( warp ) { + + var fadeInDuration = this._clip.duration, + fadeOutDuration = fadeOutAction._clip.duration, + + startEndRatio = fadeOutDuration / fadeInDuration, + endStartRatio = fadeInDuration / fadeOutDuration; + + fadeOutAction.warp( 1.0, startEndRatio, duration ); + this.warp( endStartRatio, 1.0, duration ); + + } + + return this; + + }, + + crossFadeTo: function( fadeInAction, duration, warp ) { + + return fadeInAction.crossFadeFrom( this, duration, warp ); + + }, + + stopFading: function() { + + var weightInterpolant = this._weightInterpolant; + + if ( weightInterpolant !== null ) { + + this._weightInterpolant = null; + this._mixer._takeBackControlInterpolant( weightInterpolant ); + + } + + return this; + + }, + + // Time Scale Control + + // set the weight stopping any scheduled warping + // although .paused = true yields an effective time scale of zero, this + // method does *not* change .paused, because it would be confusing + setEffectiveTimeScale: function( timeScale ) { + + this.timeScale = timeScale; + this._effectiveTimeScale = this.paused ? 0 :timeScale; + + return this.stopWarping(); + + }, + + // return the time scale considering warping and .paused + getEffectiveTimeScale: function() { + + return this._effectiveTimeScale; + + }, + + setDuration: function( duration ) { + + this.timeScale = this._clip.duration / duration; + + return this.stopWarping(); + + }, + + syncWith: function( action ) { + + this.time = action.time; + this.timeScale = action.timeScale; + + return this.stopWarping(); + + }, + + halt: function( duration ) { + + return this.warp( this._effectiveTimeScale, 0, duration ); + + }, + + warp: function( startTimeScale, endTimeScale, duration ) { + + var mixer = this._mixer, now = mixer.time, + interpolant = this._timeScaleInterpolant, + + timeScale = this.timeScale; + + if ( interpolant === null ) { + + interpolant = mixer._lendControlInterpolant(); + this._timeScaleInterpolant = interpolant; + + } + + var times = interpolant.parameterPositions, + values = interpolant.sampleValues; + + times[ 0 ] = now; + times[ 1 ] = now + duration; + + values[ 0 ] = startTimeScale / timeScale; + values[ 1 ] = endTimeScale / timeScale; + + return this; + + }, + + stopWarping: function() { + + var timeScaleInterpolant = this._timeScaleInterpolant; + + if ( timeScaleInterpolant !== null ) { + + this._timeScaleInterpolant = null; + this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); + + } + + return this; + + }, + + // Object Accessors + + getMixer: function() { + + return this._mixer; + + }, + + getClip: function() { + + return this._clip; + + }, + + getRoot: function() { + + return this._localRoot || this._mixer._root; + + }, + + // Interna + + _update: function( time, deltaTime, timeDirection, accuIndex ) { + // called by the mixer + + var startTime = this._startTime; + + if ( startTime !== null ) { + + // check for scheduled start of action + + var timeRunning = ( time - startTime ) * timeDirection; + if ( timeRunning < 0 || timeDirection === 0 ) { + + return; // yet to come / don't decide when delta = 0 + + } + + // start + + this._startTime = null; // unschedule + deltaTime = timeDirection * timeRunning; + + } + + // apply time scale and advance time + + deltaTime *= this._updateTimeScale( time ); + var clipTime = this._updateTime( deltaTime ); + + // note: _updateTime may disable the action resulting in + // an effective weight of 0 + + var weight = this._updateWeight( time ); + + if ( weight > 0 ) { + + var interpolants = this._interpolants; + var propertyMixers = this._propertyBindings; + + for ( var j = 0, m = interpolants.length; j !== m; ++ j ) { + + interpolants[ j ].evaluate( clipTime ); + propertyMixers[ j ].accumulate( accuIndex, weight ); + + } + + } + + }, + + _updateWeight: function( time ) { + + var weight = 0; + + if ( this.enabled ) { + + weight = this.weight; + var interpolant = this._weightInterpolant; + + if ( interpolant !== null ) { + + var interpolantValue = interpolant.evaluate( time )[ 0 ]; + + weight *= interpolantValue; + + if ( time > interpolant.parameterPositions[ 1 ] ) { + + this.stopFading(); + + if ( interpolantValue === 0 ) { + + // faded out, disable + this.enabled = false; + + } + + } + + } + + } + + this._effectiveWeight = weight; + return weight; + + }, + + _updateTimeScale: function( time ) { + + var timeScale = 0; + + if ( ! this.paused ) { + + timeScale = this.timeScale; + + var interpolant = this._timeScaleInterpolant; + + if ( interpolant !== null ) { + + var interpolantValue = interpolant.evaluate( time )[ 0 ]; + + timeScale *= interpolantValue; + + if ( time > interpolant.parameterPositions[ 1 ] ) { + + this.stopWarping(); + + if ( timeScale === 0 ) { + + // motion has halted, pause + this.paused = true; + + } else { + + // warp done - apply final time scale + this.timeScale = timeScale; + + } + + } + + } + + } + + this._effectiveTimeScale = timeScale; + return timeScale; + + }, + + _updateTime: function( deltaTime ) { + + var time = this.time + deltaTime; + + if ( deltaTime === 0 ) return time; + + var duration = this._clip.duration, + + loop = this.loop, + loopCount = this._loopCount; + + if ( loop === LoopOnce ) { + + if ( loopCount === -1 ) { + // just started + + this._loopCount = 0; + this._setEndings( true, true, false ); + + } + + handle_stop: { + + if ( time >= duration ) { + + time = duration; + + } else if ( time < 0 ) { + + time = 0; + + } else break handle_stop; + + if ( this.clampWhenFinished ) this.paused = true; + else this.enabled = false; + + this._mixer.dispatchEvent( { + type: 'finished', action: this, + direction: deltaTime < 0 ? -1 : 1 + } ); + + } + + } else { // repetitive Repeat or PingPong + + var pingPong = ( loop === LoopPingPong ); + + if ( loopCount === -1 ) { + // just started + + if ( deltaTime >= 0 ) { + + loopCount = 0; + + this._setEndings( + true, this.repetitions === 0, pingPong ); + + } else { + + // when looping in reverse direction, the initial + // transition through zero counts as a repetition, + // so leave loopCount at -1 + + this._setEndings( + this.repetitions === 0, true, pingPong ); + + } + + } + + if ( time >= duration || time < 0 ) { + // wrap around + + var loopDelta = Math.floor( time / duration ); // signed + time -= duration * loopDelta; + + loopCount += Math.abs( loopDelta ); + + var pending = this.repetitions - loopCount; + + if ( pending < 0 ) { + // have to stop (switch state, clamp time, fire event) + + if ( this.clampWhenFinished ) this.paused = true; + else this.enabled = false; + + time = deltaTime > 0 ? duration : 0; + + this._mixer.dispatchEvent( { + type: 'finished', action: this, + direction: deltaTime > 0 ? 1 : -1 + } ); + + } else { + // keep running + + if ( pending === 0 ) { + // entering the last round + + var atStart = deltaTime < 0; + this._setEndings( atStart, ! atStart, pingPong ); + + } else { + + this._setEndings( false, false, pingPong ); + + } + + this._loopCount = loopCount; + + this._mixer.dispatchEvent( { + type: 'loop', action: this, loopDelta: loopDelta + } ); + + } + + } + + if ( pingPong && ( loopCount & 1 ) === 1 ) { + // invert time for the "pong round" + + this.time = time; + return duration - time; + + } + + } + + this.time = time; + return time; + + }, + + _setEndings: function( atStart, atEnd, pingPong ) { + + var settings = this._interpolantSettings; + + if ( pingPong ) { + + settings.endingStart = ZeroSlopeEnding; + settings.endingEnd = ZeroSlopeEnding; + + } else { + + // assuming for LoopOnce atStart == atEnd == true + + if ( atStart ) { + + settings.endingStart = this.zeroSlopeAtStart ? + ZeroSlopeEnding : ZeroCurvatureEnding; + + } else { + + settings.endingStart = WrapAroundEnding; + + } + + if ( atEnd ) { + + settings.endingEnd = this.zeroSlopeAtEnd ? + ZeroSlopeEnding : ZeroCurvatureEnding; + + } else { + + settings.endingEnd = WrapAroundEnding; + + } + + } + + }, + + _scheduleFading: function( duration, weightNow, weightThen ) { + + var mixer = this._mixer, now = mixer.time, + interpolant = this._weightInterpolant; + + if ( interpolant === null ) { + + interpolant = mixer._lendControlInterpolant(); + this._weightInterpolant = interpolant; + + } + + var times = interpolant.parameterPositions, + values = interpolant.sampleValues; + + times[ 0 ] = now; values[ 0 ] = weightNow; + times[ 1 ] = now + duration; values[ 1 ] = weightThen; + + return this; + + } + +}; + +/** + * + * Player for AnimationClips. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ + +function AnimationMixer( root ) { + + this._root = root; + this._initMemoryManager(); + this._accuIndex = 0; + + this.time = 0; + + this.timeScale = 1.0; + +} + +AnimationMixer.prototype = { + + constructor: AnimationMixer, + + // return an action for a clip optionally using a custom root target + // object (this method allocates a lot of dynamic memory in case a + // previously unknown clip/root combination is specified) + clipAction: function ( clip, optionalRoot ) { + + var root = optionalRoot || this._root, + rootUuid = root.uuid, + + clipObject = typeof clip === 'string' ? + AnimationClip.findByName( root, clip ) : clip, + + clipUuid = clipObject !== null ? clipObject.uuid : clip, + + actionsForClip = this._actionsByClip[ clipUuid ], + prototypeAction = null; + + if ( actionsForClip !== undefined ) { + + var existingAction = + actionsForClip.actionByRoot[ rootUuid ]; + + if ( existingAction !== undefined ) { + + return existingAction; + + } + + // we know the clip, so we don't have to parse all + // the bindings again but can just copy + prototypeAction = actionsForClip.knownActions[ 0 ]; + + // also, take the clip from the prototype action + if ( clipObject === null ) + clipObject = prototypeAction._clip; + + } + + // clip must be known when specified via string + if ( clipObject === null ) return null; + + // allocate all resources required to run it + var newAction = new AnimationAction( this, clipObject, optionalRoot ); + + this._bindAction( newAction, prototypeAction ); + + // and make the action known to the memory manager + this._addInactiveAction( newAction, clipUuid, rootUuid ); + + return newAction; + + }, + + // get an existing action + existingAction: function ( clip, optionalRoot ) { + + var root = optionalRoot || this._root, + rootUuid = root.uuid, + + clipObject = typeof clip === 'string' ? + AnimationClip.findByName( root, clip ) : clip, + + clipUuid = clipObject ? clipObject.uuid : clip, + + actionsForClip = this._actionsByClip[ clipUuid ]; + + if ( actionsForClip !== undefined ) { + + return actionsForClip.actionByRoot[ rootUuid ] || null; + + } + + return null; + + }, + + // deactivates all previously scheduled actions + stopAllAction: function () { + + var actions = this._actions, + nActions = this._nActiveActions, + bindings = this._bindings, + nBindings = this._nActiveBindings; + + this._nActiveActions = 0; + this._nActiveBindings = 0; + + for ( var i = 0; i !== nActions; ++ i ) { + + actions[ i ].reset(); + + } + + for ( var i = 0; i !== nBindings; ++ i ) { + + bindings[ i ].useCount = 0; + + } + + return this; + + }, + + // advance the time and update apply the animation + update: function ( deltaTime ) { + + deltaTime *= this.timeScale; + + var actions = this._actions, + nActions = this._nActiveActions, + + time = this.time += deltaTime, + timeDirection = Math.sign( deltaTime ), + + accuIndex = this._accuIndex ^= 1; + + // run active actions + + for ( var i = 0; i !== nActions; ++ i ) { + + var action = actions[ i ]; + + if ( action.enabled ) { + + action._update( time, deltaTime, timeDirection, accuIndex ); + + } + + } + + // update scene graph + + var bindings = this._bindings, + nBindings = this._nActiveBindings; + + for ( var i = 0; i !== nBindings; ++ i ) { + + bindings[ i ].apply( accuIndex ); + + } + + return this; + + }, + + // return this mixer's root target object + getRoot: function () { + + return this._root; + + }, + + // free all resources specific to a particular clip + uncacheClip: function ( clip ) { + + var actions = this._actions, + clipUuid = clip.uuid, + actionsByClip = this._actionsByClip, + actionsForClip = actionsByClip[ clipUuid ]; + + if ( actionsForClip !== undefined ) { + + // note: just calling _removeInactiveAction would mess up the + // iteration state and also require updating the state we can + // just throw away + + var actionsToRemove = actionsForClip.knownActions; + + for ( var i = 0, n = actionsToRemove.length; i !== n; ++ i ) { + + var action = actionsToRemove[ i ]; + + this._deactivateAction( action ); + + var cacheIndex = action._cacheIndex, + lastInactiveAction = actions[ actions.length - 1 ]; + + action._cacheIndex = null; + action._byClipCacheIndex = null; + + lastInactiveAction._cacheIndex = cacheIndex; + actions[ cacheIndex ] = lastInactiveAction; + actions.pop(); + + this._removeInactiveBindingsForAction( action ); + + } + + delete actionsByClip[ clipUuid ]; + + } + + }, + + // free all resources specific to a particular root target object + uncacheRoot: function ( root ) { + + var rootUuid = root.uuid, + actionsByClip = this._actionsByClip; + + for ( var clipUuid in actionsByClip ) { + + var actionByRoot = actionsByClip[ clipUuid ].actionByRoot, + action = actionByRoot[ rootUuid ]; + + if ( action !== undefined ) { + + this._deactivateAction( action ); + this._removeInactiveAction( action ); + + } + + } + + var bindingsByRoot = this._bindingsByRootAndName, + bindingByName = bindingsByRoot[ rootUuid ]; + + if ( bindingByName !== undefined ) { + + for ( var trackName in bindingByName ) { + + var binding = bindingByName[ trackName ]; + binding.restoreOriginalState(); + this._removeInactiveBinding( binding ); + + } + + } + + }, + + // remove a targeted clip from the cache + uncacheAction: function ( clip, optionalRoot ) { + + var action = this.existingAction( clip, optionalRoot ); + + if ( action !== null ) { + + this._deactivateAction( action ); + this._removeInactiveAction( action ); + + } + + } + +}; + +// Implementation details: + +Object.assign( AnimationMixer.prototype, { + + _bindAction: function ( action, prototypeAction ) { + + var root = action._localRoot || this._root, + tracks = action._clip.tracks, + nTracks = tracks.length, + bindings = action._propertyBindings, + interpolants = action._interpolants, + rootUuid = root.uuid, + bindingsByRoot = this._bindingsByRootAndName, + bindingsByName = bindingsByRoot[ rootUuid ]; + + if ( bindingsByName === undefined ) { + + bindingsByName = {}; + bindingsByRoot[ rootUuid ] = bindingsByName; + + } + + for ( var i = 0; i !== nTracks; ++ i ) { + + var track = tracks[ i ], + trackName = track.name, + binding = bindingsByName[ trackName ]; + + if ( binding !== undefined ) { + + bindings[ i ] = binding; + + } else { + + binding = bindings[ i ]; + + if ( binding !== undefined ) { + + // existing binding, make sure the cache knows + + if ( binding._cacheIndex === null ) { + + ++ binding.referenceCount; + this._addInactiveBinding( binding, rootUuid, trackName ); + + } + + continue; + + } + + var path = prototypeAction && prototypeAction. + _propertyBindings[ i ].binding.parsedPath; + + binding = new PropertyMixer( + PropertyBinding.create( root, trackName, path ), + track.ValueTypeName, track.getValueSize() ); + + ++ binding.referenceCount; + this._addInactiveBinding( binding, rootUuid, trackName ); + + bindings[ i ] = binding; + + } + + interpolants[ i ].resultBuffer = binding.buffer; + + } + + }, + + _activateAction: function ( action ) { + + if ( ! this._isActiveAction( action ) ) { + + if ( action._cacheIndex === null ) { + + // this action has been forgotten by the cache, but the user + // appears to be still using it -> rebind + + var rootUuid = ( action._localRoot || this._root ).uuid, + clipUuid = action._clip.uuid, + actionsForClip = this._actionsByClip[ clipUuid ]; + + this._bindAction( action, + actionsForClip && actionsForClip.knownActions[ 0 ] ); + + this._addInactiveAction( action, clipUuid, rootUuid ); + + } + + var bindings = action._propertyBindings; + + // increment reference counts / sort out state + for ( var i = 0, n = bindings.length; i !== n; ++ i ) { + + var binding = bindings[ i ]; + + if ( binding.useCount ++ === 0 ) { + + this._lendBinding( binding ); + binding.saveOriginalState(); + + } + + } + + this._lendAction( action ); + + } + + }, + + _deactivateAction: function ( action ) { + + if ( this._isActiveAction( action ) ) { + + var bindings = action._propertyBindings; + + // decrement reference counts / sort out state + for ( var i = 0, n = bindings.length; i !== n; ++ i ) { + + var binding = bindings[ i ]; + + if ( -- binding.useCount === 0 ) { + + binding.restoreOriginalState(); + this._takeBackBinding( binding ); + + } + + } + + this._takeBackAction( action ); + + } + + }, + + // Memory manager + + _initMemoryManager: function () { + + this._actions = []; // 'nActiveActions' followed by inactive ones + this._nActiveActions = 0; + + this._actionsByClip = {}; + // inside: + // { + // knownActions: Array< AnimationAction > - used as prototypes + // actionByRoot: AnimationAction - lookup + // } + + + this._bindings = []; // 'nActiveBindings' followed by inactive ones + this._nActiveBindings = 0; + + this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > + + + this._controlInterpolants = []; // same game as above + this._nActiveControlInterpolants = 0; + + var scope = this; + + this.stats = { + + actions: { + get total() { return scope._actions.length; }, + get inUse() { return scope._nActiveActions; } + }, + bindings: { + get total() { return scope._bindings.length; }, + get inUse() { return scope._nActiveBindings; } + }, + controlInterpolants: { + get total() { return scope._controlInterpolants.length; }, + get inUse() { return scope._nActiveControlInterpolants; } + } + + }; + + }, + + // Memory management for AnimationAction objects + + _isActiveAction: function ( action ) { + + var index = action._cacheIndex; + return index !== null && index < this._nActiveActions; + + }, + + _addInactiveAction: function ( action, clipUuid, rootUuid ) { + + var actions = this._actions, + actionsByClip = this._actionsByClip, + actionsForClip = actionsByClip[ clipUuid ]; + + if ( actionsForClip === undefined ) { + + actionsForClip = { + + knownActions: [ action ], + actionByRoot: {} + + }; + + action._byClipCacheIndex = 0; + + actionsByClip[ clipUuid ] = actionsForClip; + + } else { + + var knownActions = actionsForClip.knownActions; + + action._byClipCacheIndex = knownActions.length; + knownActions.push( action ); + + } + + action._cacheIndex = actions.length; + actions.push( action ); + + actionsForClip.actionByRoot[ rootUuid ] = action; + + }, + + _removeInactiveAction: function ( action ) { + + var actions = this._actions, + lastInactiveAction = actions[ actions.length - 1 ], + cacheIndex = action._cacheIndex; + + lastInactiveAction._cacheIndex = cacheIndex; + actions[ cacheIndex ] = lastInactiveAction; + actions.pop(); + + action._cacheIndex = null; + + + var clipUuid = action._clip.uuid, + actionsByClip = this._actionsByClip, + actionsForClip = actionsByClip[ clipUuid ], + knownActionsForClip = actionsForClip.knownActions, + + lastKnownAction = + knownActionsForClip[ knownActionsForClip.length - 1 ], + + byClipCacheIndex = action._byClipCacheIndex; + + lastKnownAction._byClipCacheIndex = byClipCacheIndex; + knownActionsForClip[ byClipCacheIndex ] = lastKnownAction; + knownActionsForClip.pop(); + + action._byClipCacheIndex = null; + + + var actionByRoot = actionsForClip.actionByRoot, + rootUuid = ( actions._localRoot || this._root ).uuid; + + delete actionByRoot[ rootUuid ]; + + if ( knownActionsForClip.length === 0 ) { + + delete actionsByClip[ clipUuid ]; + + } + + this._removeInactiveBindingsForAction( action ); + + }, + + _removeInactiveBindingsForAction: function ( action ) { + + var bindings = action._propertyBindings; + for ( var i = 0, n = bindings.length; i !== n; ++ i ) { + + var binding = bindings[ i ]; + + if ( -- binding.referenceCount === 0 ) { + + this._removeInactiveBinding( binding ); + + } + + } + + }, + + _lendAction: function ( action ) { + + // [ active actions | inactive actions ] + // [ active actions >| inactive actions ] + // s a + // <-swap-> + // a s + + var actions = this._actions, + prevIndex = action._cacheIndex, + + lastActiveIndex = this._nActiveActions ++, + + firstInactiveAction = actions[ lastActiveIndex ]; + + action._cacheIndex = lastActiveIndex; + actions[ lastActiveIndex ] = action; + + firstInactiveAction._cacheIndex = prevIndex; + actions[ prevIndex ] = firstInactiveAction; + + }, + + _takeBackAction: function ( action ) { + + // [ active actions | inactive actions ] + // [ active actions |< inactive actions ] + // a s + // <-swap-> + // s a + + var actions = this._actions, + prevIndex = action._cacheIndex, + + firstInactiveIndex = -- this._nActiveActions, + + lastActiveAction = actions[ firstInactiveIndex ]; + + action._cacheIndex = firstInactiveIndex; + actions[ firstInactiveIndex ] = action; + + lastActiveAction._cacheIndex = prevIndex; + actions[ prevIndex ] = lastActiveAction; + + }, + + // Memory management for PropertyMixer objects + + _addInactiveBinding: function ( binding, rootUuid, trackName ) { + + var bindingsByRoot = this._bindingsByRootAndName, + bindingByName = bindingsByRoot[ rootUuid ], + + bindings = this._bindings; + + if ( bindingByName === undefined ) { + + bindingByName = {}; + bindingsByRoot[ rootUuid ] = bindingByName; + + } + + bindingByName[ trackName ] = binding; + + binding._cacheIndex = bindings.length; + bindings.push( binding ); + + }, + + _removeInactiveBinding: function ( binding ) { + + var bindings = this._bindings, + propBinding = binding.binding, + rootUuid = propBinding.rootNode.uuid, + trackName = propBinding.path, + bindingsByRoot = this._bindingsByRootAndName, + bindingByName = bindingsByRoot[ rootUuid ], + + lastInactiveBinding = bindings[ bindings.length - 1 ], + cacheIndex = binding._cacheIndex; + + lastInactiveBinding._cacheIndex = cacheIndex; + bindings[ cacheIndex ] = lastInactiveBinding; + bindings.pop(); + + delete bindingByName[ trackName ]; + + remove_empty_map: { + + for ( var _ in bindingByName ) break remove_empty_map; + + delete bindingsByRoot[ rootUuid ]; + + } + + }, + + _lendBinding: function ( binding ) { + + var bindings = this._bindings, + prevIndex = binding._cacheIndex, + + lastActiveIndex = this._nActiveBindings ++, + + firstInactiveBinding = bindings[ lastActiveIndex ]; + + binding._cacheIndex = lastActiveIndex; + bindings[ lastActiveIndex ] = binding; + + firstInactiveBinding._cacheIndex = prevIndex; + bindings[ prevIndex ] = firstInactiveBinding; + + }, + + _takeBackBinding: function ( binding ) { + + var bindings = this._bindings, + prevIndex = binding._cacheIndex, + + firstInactiveIndex = -- this._nActiveBindings, + + lastActiveBinding = bindings[ firstInactiveIndex ]; + + binding._cacheIndex = firstInactiveIndex; + bindings[ firstInactiveIndex ] = binding; + + lastActiveBinding._cacheIndex = prevIndex; + bindings[ prevIndex ] = lastActiveBinding; + + }, + + + // Memory management of Interpolants for weight and time scale + + _lendControlInterpolant: function () { + + var interpolants = this._controlInterpolants, + lastActiveIndex = this._nActiveControlInterpolants ++, + interpolant = interpolants[ lastActiveIndex ]; + + if ( interpolant === undefined ) { + + interpolant = new LinearInterpolant( + new Float32Array( 2 ), new Float32Array( 2 ), + 1, this._controlInterpolantsResultBuffer ); + + interpolant.__cacheIndex = lastActiveIndex; + interpolants[ lastActiveIndex ] = interpolant; + + } + + return interpolant; + + }, + + _takeBackControlInterpolant: function ( interpolant ) { + + var interpolants = this._controlInterpolants, + prevIndex = interpolant.__cacheIndex, + + firstInactiveIndex = -- this._nActiveControlInterpolants, + + lastActiveInterpolant = interpolants[ firstInactiveIndex ]; + + interpolant.__cacheIndex = firstInactiveIndex; + interpolants[ firstInactiveIndex ] = interpolant; + + lastActiveInterpolant.__cacheIndex = prevIndex; + interpolants[ prevIndex ] = lastActiveInterpolant; + + }, + + _controlInterpolantsResultBuffer: new Float32Array( 1 ) + +} ); + +Object.assign( AnimationMixer.prototype, EventDispatcher.prototype ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function Uniform( value ) { + + if ( typeof value === 'string' ) { + + console.warn( 'THREE.Uniform: Type parameter is no longer needed.' ); + value = arguments[ 1 ]; + + } + + this.value = value; + +} + +Uniform.prototype.clone = function () { + + return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() ); + +}; + +/** + * @author benaadams / https://twitter.com/ben_a_adams + */ + +function InstancedBufferGeometry() { + + BufferGeometry.call( this ); + + this.type = 'InstancedBufferGeometry'; + this.maxInstancedCount = undefined; + +} + +InstancedBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +InstancedBufferGeometry.prototype.constructor = InstancedBufferGeometry; + +InstancedBufferGeometry.prototype.isInstancedBufferGeometry = true; + +InstancedBufferGeometry.prototype.addGroup = function ( start, count, materialIndex ) { + + this.groups.push( { + + start: start, + count: count, + materialIndex: materialIndex + + } ); + +}; + +InstancedBufferGeometry.prototype.copy = function ( source ) { + + var index = source.index; + + if ( index !== null ) { + + this.setIndex( index.clone() ); + + } + + var attributes = source.attributes; + + for ( var name in attributes ) { + + var attribute = attributes[ name ]; + this.addAttribute( name, attribute.clone() ); + + } + + var groups = source.groups; + + for ( var i = 0, l = groups.length; i < l; i ++ ) { + + var group = groups[ i ]; + this.addGroup( group.start, group.count, group.materialIndex ); + + } + + return this; + +}; + +/** + * @author benaadams / https://twitter.com/ben_a_adams + */ + +function InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normalized ) { + + this.uuid = _Math.generateUUID(); + + this.data = interleavedBuffer; + this.itemSize = itemSize; + this.offset = offset; + + this.normalized = normalized === true; + +} + + +InterleavedBufferAttribute.prototype = { + + constructor: InterleavedBufferAttribute, + + isInterleavedBufferAttribute: true, + + get count() { + + return this.data.count; + + }, + + get array() { + + return this.data.array; + + }, + + setX: function ( index, x ) { + + this.data.array[ index * this.data.stride + this.offset ] = x; + + return this; + + }, + + setY: function ( index, y ) { + + this.data.array[ index * this.data.stride + this.offset + 1 ] = y; + + return this; + + }, + + setZ: function ( index, z ) { + + this.data.array[ index * this.data.stride + this.offset + 2 ] = z; + + return this; + + }, + + setW: function ( index, w ) { + + this.data.array[ index * this.data.stride + this.offset + 3 ] = w; + + return this; + + }, + + getX: function ( index ) { + + return this.data.array[ index * this.data.stride + this.offset ]; + + }, + + getY: function ( index ) { + + return this.data.array[ index * this.data.stride + this.offset + 1 ]; + + }, + + getZ: function ( index ) { + + return this.data.array[ index * this.data.stride + this.offset + 2 ]; + + }, + + getW: function ( index ) { + + return this.data.array[ index * this.data.stride + this.offset + 3 ]; + + }, + + setXY: function ( index, x, y ) { + + index = index * this.data.stride + this.offset; + + this.data.array[ index + 0 ] = x; + this.data.array[ index + 1 ] = y; + + return this; + + }, + + setXYZ: function ( index, x, y, z ) { + + index = index * this.data.stride + this.offset; + + this.data.array[ index + 0 ] = x; + this.data.array[ index + 1 ] = y; + this.data.array[ index + 2 ] = z; + + return this; + + }, + + setXYZW: function ( index, x, y, z, w ) { + + index = index * this.data.stride + this.offset; + + this.data.array[ index + 0 ] = x; + this.data.array[ index + 1 ] = y; + this.data.array[ index + 2 ] = z; + this.data.array[ index + 3 ] = w; + + return this; + + } + +}; + +/** + * @author benaadams / https://twitter.com/ben_a_adams + */ + +function InterleavedBuffer( array, stride ) { + + this.uuid = _Math.generateUUID(); + + this.array = array; + this.stride = stride; + this.count = array !== undefined ? array.length / stride : 0; + + this.dynamic = false; + this.updateRange = { offset: 0, count: - 1 }; + + this.onUploadCallback = function () {}; + + this.version = 0; + +} + +InterleavedBuffer.prototype = { + + constructor: InterleavedBuffer, + + isInterleavedBuffer: true, + + set needsUpdate( value ) { + + if ( value === true ) this.version ++; + + }, + + setArray: function ( array ) { + + if ( Array.isArray( array ) ) { + + throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); + + } + + this.count = array !== undefined ? array.length / this.stride : 0; + this.array = array; + + }, + + setDynamic: function ( value ) { + + this.dynamic = value; + + return this; + + }, + + copy: function ( source ) { + + this.array = new source.array.constructor( source.array ); + this.count = source.count; + this.stride = source.stride; + this.dynamic = source.dynamic; + + return this; + + }, + + copyAt: function ( index1, attribute, index2 ) { + + index1 *= this.stride; + index2 *= attribute.stride; + + for ( var i = 0, l = this.stride; i < l; i ++ ) { + + this.array[ index1 + i ] = attribute.array[ index2 + i ]; + + } + + return this; + + }, + + set: function ( value, offset ) { + + if ( offset === undefined ) offset = 0; + + this.array.set( value, offset ); + + return this; + + }, + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + onUpload: function ( callback ) { + + this.onUploadCallback = callback; + + return this; + + } + +}; + +/** + * @author benaadams / https://twitter.com/ben_a_adams + */ + +function InstancedInterleavedBuffer( array, stride, meshPerAttribute ) { + + InterleavedBuffer.call( this, array, stride ); + + this.meshPerAttribute = meshPerAttribute || 1; + +} + +InstancedInterleavedBuffer.prototype = Object.create( InterleavedBuffer.prototype ); +InstancedInterleavedBuffer.prototype.constructor = InstancedInterleavedBuffer; + +InstancedInterleavedBuffer.prototype.isInstancedInterleavedBuffer = true; + +InstancedInterleavedBuffer.prototype.copy = function ( source ) { + + InterleavedBuffer.prototype.copy.call( this, source ); + + this.meshPerAttribute = source.meshPerAttribute; + + return this; + +}; + +/** + * @author benaadams / https://twitter.com/ben_a_adams + */ + +function InstancedBufferAttribute( array, itemSize, meshPerAttribute ) { + + BufferAttribute.call( this, array, itemSize ); + + this.meshPerAttribute = meshPerAttribute || 1; + +} + +InstancedBufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +InstancedBufferAttribute.prototype.constructor = InstancedBufferAttribute; + +InstancedBufferAttribute.prototype.isInstancedBufferAttribute = true; + +InstancedBufferAttribute.prototype.copy = function ( source ) { + + BufferAttribute.prototype.copy.call( this, source ); + + this.meshPerAttribute = source.meshPerAttribute; + + return this; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author bhouston / http://clara.io/ + * @author stephomi / http://stephaneginier.com/ + */ + +function Raycaster( origin, direction, near, far ) { + + this.ray = new Ray( origin, direction ); + // direction is assumed to be normalized (for accurate distance calculations) + + this.near = near || 0; + this.far = far || Infinity; + + this.params = { + Mesh: {}, + Line: {}, + LOD: {}, + Points: { threshold: 1 }, + Sprite: {} + }; + + Object.defineProperties( this.params, { + PointCloud: { + get: function () { + console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' ); + return this.Points; + } + } + } ); + +} + +function ascSort( a, b ) { + + return a.distance - b.distance; + +} + +function intersectObject( object, raycaster, intersects, recursive ) { + + if ( object.visible === false ) return; + + object.raycast( raycaster, intersects ); + + if ( recursive === true ) { + + var children = object.children; + + for ( var i = 0, l = children.length; i < l; i ++ ) { + + intersectObject( children[ i ], raycaster, intersects, true ); + + } + + } + +} + +// + +Raycaster.prototype = { + + constructor: Raycaster, + + linePrecision: 1, + + set: function ( origin, direction ) { + + // direction is assumed to be normalized (for accurate distance calculations) + + this.ray.set( origin, direction ); + + }, + + setFromCamera: function ( coords, camera ) { + + if ( (camera && camera.isPerspectiveCamera) ) { + + this.ray.origin.setFromMatrixPosition( camera.matrixWorld ); + this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize(); + + } else if ( (camera && camera.isOrthographicCamera) ) { + + this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera + this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); + + } else { + + console.error( 'THREE.Raycaster: Unsupported camera type.' ); + + } + + }, + + intersectObject: function ( object, recursive ) { + + var intersects = []; + + intersectObject( object, this, intersects, recursive ); + + intersects.sort( ascSort ); + + return intersects; + + }, + + intersectObjects: function ( objects, recursive ) { + + var intersects = []; + + if ( Array.isArray( objects ) === false ) { + + console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' ); + return intersects; + + } + + for ( var i = 0, l = objects.length; i < l; i ++ ) { + + intersectObject( objects[ i ], this, intersects, recursive ); + + } + + intersects.sort( ascSort ); + + return intersects; + + } + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +function Clock( autoStart ) { + + this.autoStart = ( autoStart !== undefined ) ? autoStart : true; + + this.startTime = 0; + this.oldTime = 0; + this.elapsedTime = 0; + + this.running = false; + +} + +Clock.prototype = { + + constructor: Clock, + + start: function () { + + this.startTime = ( performance || Date ).now(); + + this.oldTime = this.startTime; + this.elapsedTime = 0; + this.running = true; + + }, + + stop: function () { + + this.getElapsedTime(); + this.running = false; + + }, + + getElapsedTime: function () { + + this.getDelta(); + return this.elapsedTime; + + }, + + getDelta: function () { + + var diff = 0; + + if ( this.autoStart && ! this.running ) { + + this.start(); + + } + + if ( this.running ) { + + var newTime = ( performance || Date ).now(); + + diff = ( newTime - this.oldTime ) / 1000; + this.oldTime = newTime; + + this.elapsedTime += diff; + + } + + return diff; + + } + +}; + +/** + * @author bhouston / http://clara.io + * @author WestLangley / http://github.com/WestLangley + * + * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system + * + * The poles (phi) are at the positive and negative y axis. + * The equator starts at positive z. + */ + +function Spherical( radius, phi, theta ) { + + this.radius = ( radius !== undefined ) ? radius : 1.0; + this.phi = ( phi !== undefined ) ? phi : 0; // up / down towards top and bottom pole + this.theta = ( theta !== undefined ) ? theta : 0; // around the equator of the sphere + + return this; + +} + +Spherical.prototype = { + + constructor: Spherical, + + set: function ( radius, phi, theta ) { + + this.radius = radius; + this.phi = phi; + this.theta = theta; + + return this; + + }, + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + copy: function ( other ) { + + this.radius = other.radius; + this.phi = other.phi; + this.theta = other.theta; + + return this; + + }, + + // restrict phi to be betwee EPS and PI-EPS + makeSafe: function() { + + var EPS = 0.000001; + this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) ); + + return this; + + }, + + setFromVector3: function( vec3 ) { + + this.radius = vec3.length(); + + if ( this.radius === 0 ) { + + this.theta = 0; + this.phi = 0; + + } else { + + this.theta = Math.atan2( vec3.x, vec3.z ); // equator angle around y-up axis + this.phi = Math.acos( _Math.clamp( vec3.y / this.radius, - 1, 1 ) ); // polar angle + + } + + return this; + + } + +}; + +/** + * @author Mugen87 / https://github.com/Mugen87 + * + * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system + * + */ + +function Cylindrical( radius, theta, y ) { + + this.radius = ( radius !== undefined ) ? radius : 1.0; // distance from the origin to a point in the x-z plane + this.theta = ( theta !== undefined ) ? theta : 0; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis + this.y = ( y !== undefined ) ? y : 0; // height above the x-z plane + + return this; + +} + +Cylindrical.prototype = { + + constructor: Cylindrical, + + set: function ( radius, theta, y ) { + + this.radius = radius; + this.theta = theta; + this.y = y; + + return this; + + }, + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + copy: function ( other ) { + + this.radius = other.radius; + this.theta = other.theta; + this.y = other.y; + + return this; + + }, + + setFromVector3: function( vec3 ) { + + this.radius = Math.sqrt( vec3.x * vec3.x + vec3.z * vec3.z ); + this.theta = Math.atan2( vec3.x, vec3.z ); + this.y = vec3.y; + + return this; + + } + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +function MorphBlendMesh( geometry, material ) { + + Mesh.call( this, geometry, material ); + + this.animationsMap = {}; + this.animationsList = []; + + // prepare default animation + // (all frames played together in 1 second) + + var numFrames = this.geometry.morphTargets.length; + + var name = "__default"; + + var startFrame = 0; + var endFrame = numFrames - 1; + + var fps = numFrames / 1; + + this.createAnimation( name, startFrame, endFrame, fps ); + this.setAnimationWeight( name, 1 ); + +} + +MorphBlendMesh.prototype = Object.create( Mesh.prototype ); +MorphBlendMesh.prototype.constructor = MorphBlendMesh; + +MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) { + + var animation = { + + start: start, + end: end, + + length: end - start + 1, + + fps: fps, + duration: ( end - start ) / fps, + + lastFrame: 0, + currentFrame: 0, + + active: false, + + time: 0, + direction: 1, + weight: 1, + + directionBackwards: false, + mirroredLoop: false + + }; + + this.animationsMap[ name ] = animation; + this.animationsList.push( animation ); + +}; + +MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) { + + var pattern = /([a-z]+)_?(\d+)/i; + + var firstAnimation, frameRanges = {}; + + var geometry = this.geometry; + + for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { + + var morph = geometry.morphTargets[ i ]; + var chunks = morph.name.match( pattern ); + + if ( chunks && chunks.length > 1 ) { + + var name = chunks[ 1 ]; + + if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: - Infinity }; + + var range = frameRanges[ name ]; + + if ( i < range.start ) range.start = i; + if ( i > range.end ) range.end = i; + + if ( ! firstAnimation ) firstAnimation = name; + + } + + } + + for ( var name in frameRanges ) { + + var range = frameRanges[ name ]; + this.createAnimation( name, range.start, range.end, fps ); + + } + + this.firstAnimation = firstAnimation; + +}; + +MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.direction = 1; + animation.directionBackwards = false; + + } + +}; + +MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.direction = - 1; + animation.directionBackwards = true; + + } + +}; + +MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.fps = fps; + animation.duration = ( animation.end - animation.start ) / animation.fps; + + } + +}; + +MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.duration = duration; + animation.fps = ( animation.end - animation.start ) / animation.duration; + + } + +}; + +MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.weight = weight; + + } + +}; + +MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.time = time; + + } + +}; + +MorphBlendMesh.prototype.getAnimationTime = function ( name ) { + + var time = 0; + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + time = animation.time; + + } + + return time; + +}; + +MorphBlendMesh.prototype.getAnimationDuration = function ( name ) { + + var duration = - 1; + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + duration = animation.duration; + + } + + return duration; + +}; + +MorphBlendMesh.prototype.playAnimation = function ( name ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.time = 0; + animation.active = true; + + } else { + + console.warn( "THREE.MorphBlendMesh: animation[" + name + "] undefined in .playAnimation()" ); + + } + +}; + +MorphBlendMesh.prototype.stopAnimation = function ( name ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.active = false; + + } + +}; + +MorphBlendMesh.prototype.update = function ( delta ) { + + for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) { + + var animation = this.animationsList[ i ]; + + if ( ! animation.active ) continue; + + var frameTime = animation.duration / animation.length; + + animation.time += animation.direction * delta; + + if ( animation.mirroredLoop ) { + + if ( animation.time > animation.duration || animation.time < 0 ) { + + animation.direction *= - 1; + + if ( animation.time > animation.duration ) { + + animation.time = animation.duration; + animation.directionBackwards = true; + + } + + if ( animation.time < 0 ) { + + animation.time = 0; + animation.directionBackwards = false; + + } + + } + + } else { + + animation.time = animation.time % animation.duration; + + if ( animation.time < 0 ) animation.time += animation.duration; + + } + + var keyframe = animation.start + _Math.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 ); + var weight = animation.weight; + + if ( keyframe !== animation.currentFrame ) { + + this.morphTargetInfluences[ animation.lastFrame ] = 0; + this.morphTargetInfluences[ animation.currentFrame ] = 1 * weight; + + this.morphTargetInfluences[ keyframe ] = 0; + + animation.lastFrame = animation.currentFrame; + animation.currentFrame = keyframe; + + } + + var mix = ( animation.time % frameTime ) / frameTime; + + if ( animation.directionBackwards ) mix = 1 - mix; + + if ( animation.currentFrame !== animation.lastFrame ) { + + this.morphTargetInfluences[ animation.currentFrame ] = mix * weight; + this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight; + + } else { + + this.morphTargetInfluences[ animation.currentFrame ] = weight; + + } + + } + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +function ImmediateRenderObject( material ) { + + Object3D.call( this ); + + this.material = material; + this.render = function ( renderCallback ) {}; + +} + +ImmediateRenderObject.prototype = Object.create( Object3D.prototype ); +ImmediateRenderObject.prototype.constructor = ImmediateRenderObject; + +ImmediateRenderObject.prototype.isImmediateRenderObject = true; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ + +function VertexNormalsHelper( object, size, hex, linewidth ) { + + this.object = object; + + this.size = ( size !== undefined ) ? size : 1; + + var color = ( hex !== undefined ) ? hex : 0xff0000; + + var width = ( linewidth !== undefined ) ? linewidth : 1; + + // + + var nNormals = 0; + + var objGeometry = this.object.geometry; + + if ( objGeometry && objGeometry.isGeometry ) { + + nNormals = objGeometry.faces.length * 3; + + } else if ( objGeometry && objGeometry.isBufferGeometry ) { + + nNormals = objGeometry.attributes.normal.count; + + } + + // + + var geometry = new BufferGeometry(); + + var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 ); + + geometry.addAttribute( 'position', positions ); + + LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) ); + + // + + this.matrixAutoUpdate = false; + + this.update(); + +} + +VertexNormalsHelper.prototype = Object.create( LineSegments.prototype ); +VertexNormalsHelper.prototype.constructor = VertexNormalsHelper; + +VertexNormalsHelper.prototype.update = ( function () { + + var v1 = new Vector3(); + var v2 = new Vector3(); + var normalMatrix = new Matrix3(); + + return function update() { + + var keys = [ 'a', 'b', 'c' ]; + + this.object.updateMatrixWorld( true ); + + normalMatrix.getNormalMatrix( this.object.matrixWorld ); + + var matrixWorld = this.object.matrixWorld; + + var position = this.geometry.attributes.position; + + // + + var objGeometry = this.object.geometry; + + if ( objGeometry && objGeometry.isGeometry ) { + + var vertices = objGeometry.vertices; + + var faces = objGeometry.faces; + + var idx = 0; + + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + var face = faces[ i ]; + + for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { + + var vertex = vertices[ face[ keys[ j ] ] ]; + + var normal = face.vertexNormals[ j ]; + + v1.copy( vertex ).applyMatrix4( matrixWorld ); + + v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); + + position.setXYZ( idx, v1.x, v1.y, v1.z ); + + idx = idx + 1; + + position.setXYZ( idx, v2.x, v2.y, v2.z ); + + idx = idx + 1; + + } + + } + + } else if ( objGeometry && objGeometry.isBufferGeometry ) { + + var objPos = objGeometry.attributes.position; + + var objNorm = objGeometry.attributes.normal; + + var idx = 0; + + // for simplicity, ignore index and drawcalls, and render every normal + + for ( var j = 0, jl = objPos.count; j < jl; j ++ ) { + + v1.set( objPos.getX( j ), objPos.getY( j ), objPos.getZ( j ) ).applyMatrix4( matrixWorld ); + + v2.set( objNorm.getX( j ), objNorm.getY( j ), objNorm.getZ( j ) ); + + v2.applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); + + position.setXYZ( idx, v1.x, v1.y, v1.z ); + + idx = idx + 1; + + position.setXYZ( idx, v2.x, v2.y, v2.z ); + + idx = idx + 1; + + } + + } + + position.needsUpdate = true; + + return this; + + }; + +}() ); + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ + +function SpotLightHelper( light ) { + + Object3D.call( this ); + + this.light = light; + this.light.updateMatrixWorld(); + + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; + + var geometry = new BufferGeometry(); + + var positions = [ + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 1, 0, 1, + 0, 0, 0, - 1, 0, 1, + 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, - 1, 1 + ]; + + for ( var i = 0, j = 1, l = 32; i < l; i ++, j ++ ) { + + var p1 = ( i / l ) * Math.PI * 2; + var p2 = ( j / l ) * Math.PI * 2; + + positions.push( + Math.cos( p1 ), Math.sin( p1 ), 1, + Math.cos( p2 ), Math.sin( p2 ), 1 + ); + + } + + geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + + var material = new LineBasicMaterial( { fog: false } ); + + this.cone = new LineSegments( geometry, material ); + this.add( this.cone ); + + this.update(); + +} + +SpotLightHelper.prototype = Object.create( Object3D.prototype ); +SpotLightHelper.prototype.constructor = SpotLightHelper; + +SpotLightHelper.prototype.dispose = function () { + + this.cone.geometry.dispose(); + this.cone.material.dispose(); + +}; + +SpotLightHelper.prototype.update = function () { + + var vector = new Vector3(); + var vector2 = new Vector3(); + + return function update() { + + var coneLength = this.light.distance ? this.light.distance : 1000; + var coneWidth = coneLength * Math.tan( this.light.angle ); + + this.cone.scale.set( coneWidth, coneWidth, coneLength ); + + vector.setFromMatrixPosition( this.light.matrixWorld ); + vector2.setFromMatrixPosition( this.light.target.matrixWorld ); + + this.cone.lookAt( vector2.sub( vector ) ); + + this.cone.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + + }; + +}(); + +/** + * @author Sean Griffin / http://twitter.com/sgrif + * @author Michael Guerrero / http://realitymeltdown.com + * @author mrdoob / http://mrdoob.com/ + * @author ikerr / http://verold.com + * @author Mugen87 / https://github.com/Mugen87 + */ + +function SkeletonHelper( object ) { + + this.bones = this.getBoneList( object ); + + var geometry = new BufferGeometry(); + + var vertices = []; + var colors = []; + + var color1 = new Color( 0, 0, 1 ); + var color2 = new Color( 0, 1, 0 ); + + for ( var i = 0; i < this.bones.length; i ++ ) { + + var bone = this.bones[ i ]; + + if ( bone.parent && bone.parent.isBone ) { + + vertices.push( 0, 0, 0 ); + vertices.push( 0, 0, 0 ); + colors.push( color1.r, color1.g, color1.b ); + colors.push( color2.r, color2.g, color2.b ); + + } + + } + + geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + + var material = new LineBasicMaterial( { vertexColors: VertexColors, depthTest: false, depthWrite: false, transparent: true } ); + + LineSegments.call( this, geometry, material ); + + this.root = object; + + this.matrix = object.matrixWorld; + this.matrixAutoUpdate = false; + + this.update(); + +} + + +SkeletonHelper.prototype = Object.create( LineSegments.prototype ); +SkeletonHelper.prototype.constructor = SkeletonHelper; + +SkeletonHelper.prototype.getBoneList = function( object ) { + + var boneList = []; + + if ( object && object.isBone ) { + + boneList.push( object ); + + } + + for ( var i = 0; i < object.children.length; i ++ ) { + + boneList.push.apply( boneList, this.getBoneList( object.children[ i ] ) ); + + } + + return boneList; + +}; + +SkeletonHelper.prototype.update = function () { + + var vector = new Vector3(); + + var boneMatrix = new Matrix4(); + var matrixWorldInv = new Matrix4(); + + return function update() { + + var geometry = this.geometry; + var position = geometry.getAttribute( 'position' ); + + matrixWorldInv.getInverse( this.root.matrixWorld ); + + for ( var i = 0, j = 0; i < this.bones.length; i ++ ) { + + var bone = this.bones[ i ]; + + if ( bone.parent && bone.parent.isBone ) { + + boneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld ); + vector.setFromMatrixPosition( boneMatrix ); + position.setXYZ( j, vector.x, vector.y, vector.z ); + + boneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld ); + vector.setFromMatrixPosition( boneMatrix ); + position.setXYZ( j + 1, vector.x, vector.y, vector.z ); + + j += 2; + + } + + } + + geometry.getAttribute( 'position' ).needsUpdate = true; + + }; + +}(); + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ + +function PointLightHelper( light, sphereSize ) { + + this.light = light; + this.light.updateMatrixWorld(); + + var geometry = new SphereBufferGeometry( sphereSize, 4, 2 ); + var material = new MeshBasicMaterial( { wireframe: true, fog: false } ); + material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + + Mesh.call( this, geometry, material ); + + this.matrix = this.light.matrixWorld; + this.matrixAutoUpdate = false; + + /* + var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); + var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); + + this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); + this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); + + var d = light.distance; + + if ( d === 0.0 ) { + + this.lightDistance.visible = false; + + } else { + + this.lightDistance.scale.set( d, d, d ); + + } + + this.add( this.lightDistance ); + */ + +} + +PointLightHelper.prototype = Object.create( Mesh.prototype ); +PointLightHelper.prototype.constructor = PointLightHelper; + +PointLightHelper.prototype.dispose = function () { + + this.geometry.dispose(); + this.material.dispose(); + +}; + +PointLightHelper.prototype.update = function () { + + this.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + + /* + var d = this.light.distance; + + if ( d === 0.0 ) { + + this.lightDistance.visible = false; + + } else { + + this.lightDistance.visible = true; + this.lightDistance.scale.set( d, d, d ); + + } + */ + +}; + +/** + * @author abelnation / http://github.com/abelnation + * @author Mugen87 / http://github.com/Mugen87 + */ + +function RectAreaLightHelper( light ) { + + Object3D.call( this ); + + this.light = light; + this.light.updateMatrixWorld(); + + var materialFront = new MeshBasicMaterial( { + color: light.color, + fog: false + } ); + + var materialBack = new MeshBasicMaterial( { + color: light.color, + fog: false, + wireframe: true + } ); + + var geometry = new BufferGeometry(); + + geometry.addAttribute( 'position', new BufferAttribute( new Float32Array( 6 * 3 ), 3 ) ); + + // shows the "front" of the light, e.g. where light comes from + + this.add( new Mesh( geometry, materialFront ) ); + + // shows the "back" of the light, which does not emit light + + this.add( new Mesh( geometry, materialBack ) ); + + this.update(); + +} + +RectAreaLightHelper.prototype = Object.create( Object3D.prototype ); +RectAreaLightHelper.prototype.constructor = RectAreaLightHelper; + +RectAreaLightHelper.prototype.dispose = function () { + + this.children[ 0 ].geometry.dispose(); + this.children[ 0 ].material.dispose(); + this.children[ 1 ].geometry.dispose(); + this.children[ 1 ].material.dispose(); + +}; + +RectAreaLightHelper.prototype.update = function () { + + var vector1 = new Vector3(); + var vector2 = new Vector3(); + + return function update() { + + var mesh1 = this.children[ 0 ]; + var mesh2 = this.children[ 1 ]; + + if ( this.light.target ) { + + vector1.setFromMatrixPosition( this.light.matrixWorld ); + vector2.setFromMatrixPosition( this.light.target.matrixWorld ); + + var lookVec = vector2.clone().sub( vector1 ); + mesh1.lookAt( lookVec ); + mesh2.lookAt( lookVec ); + + } + + // update materials + + mesh1.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + mesh2.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + + // calculate new dimensions of the helper + + var hx = this.light.width * 0.5; + var hy = this.light.height * 0.5; + + // because the buffer attribute is shared over both geometries, we only have to update once + + var position = mesh1.geometry.getAttribute( 'position' ); + var array = position.array; + + // first face + + array[ 0 ] = hx; array[ 1 ] = - hy; array[ 2 ] = 0; + array[ 3 ] = hx; array[ 4 ] = hy; array[ 5 ] = 0; + array[ 6 ] = - hx; array[ 7 ] = hy; array[ 8 ] = 0; + + // second face + + array[ 9 ] = - hx; array[ 10 ] = hy; array[ 11 ] = 0; + array[ 12 ] = - hx; array[ 13 ] = - hy; array[ 14 ] = 0; + array[ 15 ] = hx; array[ 16 ] = - hy; array[ 17 ] = 0; + + position.needsUpdate = true; + + }; + +}(); + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author Mugen87 / https://github.com/Mugen87 + */ + +function HemisphereLightHelper( light, size ) { + + Object3D.call( this ); + + this.light = light; + this.light.updateMatrixWorld(); + + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; + + var geometry = new OctahedronBufferGeometry( size ); + geometry.rotateY( Math.PI * 0.5 ); + + var material = new MeshBasicMaterial( { vertexColors: VertexColors, wireframe: true } ); + + var position = geometry.getAttribute( 'position' ); + var colors = new Float32Array( position.count * 3 ); + + geometry.addAttribute( 'color', new BufferAttribute( colors, 3 ) ); + + this.add( new Mesh( geometry, material ) ); + + this.update(); + +} + +HemisphereLightHelper.prototype = Object.create( Object3D.prototype ); +HemisphereLightHelper.prototype.constructor = HemisphereLightHelper; + +HemisphereLightHelper.prototype.dispose = function () { + + this.children[ 0 ].geometry.dispose(); + this.children[ 0 ].material.dispose(); + +}; + +HemisphereLightHelper.prototype.update = function () { + + var vector = new Vector3(); + + var color1 = new Color(); + var color2 = new Color(); + + return function update() { + + var mesh = this.children[ 0 ]; + + var colors = mesh.geometry.getAttribute( 'color' ); + + color1.copy( this.light.color ).multiplyScalar( this.light.intensity ); + color2.copy( this.light.groundColor ).multiplyScalar( this.light.intensity ); + + for ( var i = 0, l = colors.count; i < l; i ++ ) { + + var color = ( i < ( l / 2 ) ) ? color1 : color2; + + colors.setXYZ( i, color.r, color.g, color.b ); + + } + + mesh.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() ); + + colors.needsUpdate = true; + + }; + +}(); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function GridHelper( size, divisions, color1, color2 ) { + + size = size || 10; + divisions = divisions || 10; + color1 = new Color( color1 !== undefined ? color1 : 0x444444 ); + color2 = new Color( color2 !== undefined ? color2 : 0x888888 ); + + var center = divisions / 2; + var step = size / divisions; + var halfSize = size / 2; + + var vertices = [], colors = []; + + for ( var i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) { + + vertices.push( - halfSize, 0, k, halfSize, 0, k ); + vertices.push( k, 0, - halfSize, k, 0, halfSize ); + + var color = i === center ? color1 : color2; + + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; + + } + + var geometry = new BufferGeometry(); + geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + + var material = new LineBasicMaterial( { vertexColors: VertexColors } ); + + LineSegments.call( this, geometry, material ); + +} + +GridHelper.prototype = Object.create( LineSegments.prototype ); +GridHelper.prototype.constructor = GridHelper; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author Mugen87 / http://github.com/Mugen87 + * @author Hectate / http://www.github.com/Hectate + */ + +function PolarGridHelper( radius, radials, circles, divisions, color1, color2 ) { + + radius = radius || 10; + radials = radials || 16; + circles = circles || 8; + divisions = divisions || 64; + color1 = new Color( color1 !== undefined ? color1 : 0x444444 ); + color2 = new Color( color2 !== undefined ? color2 : 0x888888 ); + + var vertices = []; + var colors = []; + + var x, z; + var v, i, j, r, color; + + // create the radials + + for ( i = 0; i <= radials; i ++ ) { + + v = ( i / radials ) * ( Math.PI * 2 ); + + x = Math.sin( v ) * radius; + z = Math.cos( v ) * radius; + + vertices.push( 0, 0, 0 ); + vertices.push( x, 0, z ); + + color = ( i & 1 ) ? color1 : color2; + + colors.push( color.r, color.g, color.b ); + colors.push( color.r, color.g, color.b ); + + } + + // create the circles + + for ( i = 0; i <= circles; i ++ ) { + + color = ( i & 1 ) ? color1 : color2; + + r = radius - ( radius / circles * i ); + + for ( j = 0; j < divisions; j ++ ) { + + // first vertex + + v = ( j / divisions ) * ( Math.PI * 2 ); + + x = Math.sin( v ) * r; + z = Math.cos( v ) * r; + + vertices.push( x, 0, z ); + colors.push( color.r, color.g, color.b ); + + // second vertex + + v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 ); + + x = Math.sin( v ) * r; + z = Math.cos( v ) * r; + + vertices.push( x, 0, z ); + colors.push( color.r, color.g, color.b ); + + } + + } + + var geometry = new BufferGeometry(); + geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + + var material = new LineBasicMaterial( { vertexColors: VertexColors } ); + + LineSegments.call( this, geometry, material ); + +} + +PolarGridHelper.prototype = Object.create( LineSegments.prototype ); +PolarGridHelper.prototype.constructor = PolarGridHelper; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ + +function FaceNormalsHelper( object, size, hex, linewidth ) { + + // FaceNormalsHelper only supports THREE.Geometry + + this.object = object; + + this.size = ( size !== undefined ) ? size : 1; + + var color = ( hex !== undefined ) ? hex : 0xffff00; + + var width = ( linewidth !== undefined ) ? linewidth : 1; + + // + + var nNormals = 0; + + var objGeometry = this.object.geometry; + + if ( objGeometry && objGeometry.isGeometry ) { + + nNormals = objGeometry.faces.length; + + } else { + + console.warn( 'THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead.' ); + + } + + // + + var geometry = new BufferGeometry(); + + var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 ); + + geometry.addAttribute( 'position', positions ); + + LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) ); + + // + + this.matrixAutoUpdate = false; + this.update(); + +} + +FaceNormalsHelper.prototype = Object.create( LineSegments.prototype ); +FaceNormalsHelper.prototype.constructor = FaceNormalsHelper; + +FaceNormalsHelper.prototype.update = ( function () { + + var v1 = new Vector3(); + var v2 = new Vector3(); + var normalMatrix = new Matrix3(); + + return function update() { + + this.object.updateMatrixWorld( true ); + + normalMatrix.getNormalMatrix( this.object.matrixWorld ); + + var matrixWorld = this.object.matrixWorld; + + var position = this.geometry.attributes.position; + + // + + var objGeometry = this.object.geometry; + + var vertices = objGeometry.vertices; + + var faces = objGeometry.faces; + + var idx = 0; + + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + var face = faces[ i ]; + + var normal = face.normal; + + v1.copy( vertices[ face.a ] ) + .add( vertices[ face.b ] ) + .add( vertices[ face.c ] ) + .divideScalar( 3 ) + .applyMatrix4( matrixWorld ); + + v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); + + position.setXYZ( idx, v1.x, v1.y, v1.z ); + + idx = idx + 1; + + position.setXYZ( idx, v2.x, v2.y, v2.z ); + + idx = idx + 1; + + } + + position.needsUpdate = true; + + return this; + + }; + +}() ); + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley + */ + +function DirectionalLightHelper( light, size ) { + + Object3D.call( this ); + + this.light = light; + this.light.updateMatrixWorld(); + + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; + + if ( size === undefined ) size = 1; + + var geometry = new BufferGeometry(); + geometry.addAttribute( 'position', new Float32BufferAttribute( [ + - size, size, 0, + size, size, 0, + size, - size, 0, + - size, - size, 0, + - size, size, 0 + ], 3 ) ); + + var material = new LineBasicMaterial( { fog: false } ); + + this.add( new Line( geometry, material ) ); + + geometry = new BufferGeometry(); + geometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); + + this.add( new Line( geometry, material )); + + this.update(); + +} + +DirectionalLightHelper.prototype = Object.create( Object3D.prototype ); +DirectionalLightHelper.prototype.constructor = DirectionalLightHelper; + +DirectionalLightHelper.prototype.dispose = function () { + + var lightPlane = this.children[ 0 ]; + var targetLine = this.children[ 1 ]; + + lightPlane.geometry.dispose(); + lightPlane.material.dispose(); + targetLine.geometry.dispose(); + targetLine.material.dispose(); + +}; + +DirectionalLightHelper.prototype.update = function () { + + var v1 = new Vector3(); + var v2 = new Vector3(); + var v3 = new Vector3(); + + return function update() { + + v1.setFromMatrixPosition( this.light.matrixWorld ); + v2.setFromMatrixPosition( this.light.target.matrixWorld ); + v3.subVectors( v2, v1 ); + + var lightPlane = this.children[ 0 ]; + var targetLine = this.children[ 1 ]; + + lightPlane.lookAt( v3 ); + lightPlane.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + + targetLine.lookAt( v3 ); + targetLine.scale.z = v3.length(); + + }; + +}(); + +/** + * @author alteredq / http://alteredqualia.com/ + * @author Mugen87 / https://github.com/Mugen87 + * + * - shows frustum, line of sight and up of the camera + * - suitable for fast updates + * - based on frustum visualization in lightgl.js shadowmap example + * http://evanw.github.com/lightgl.js/tests/shadowmap.html + */ + +function CameraHelper( camera ) { + + var geometry = new BufferGeometry(); + var material = new LineBasicMaterial( { color: 0xffffff, vertexColors: FaceColors } ); + + var vertices = []; + var colors = []; + + var pointMap = {}; + + // colors + + var colorFrustum = new Color( 0xffaa00 ); + var colorCone = new Color( 0xff0000 ); + var colorUp = new Color( 0x00aaff ); + var colorTarget = new Color( 0xffffff ); + var colorCross = new Color( 0x333333 ); + + // near + + addLine( "n1", "n2", colorFrustum ); + addLine( "n2", "n4", colorFrustum ); + addLine( "n4", "n3", colorFrustum ); + addLine( "n3", "n1", colorFrustum ); + + // far + + addLine( "f1", "f2", colorFrustum ); + addLine( "f2", "f4", colorFrustum ); + addLine( "f4", "f3", colorFrustum ); + addLine( "f3", "f1", colorFrustum ); + + // sides + + addLine( "n1", "f1", colorFrustum ); + addLine( "n2", "f2", colorFrustum ); + addLine( "n3", "f3", colorFrustum ); + addLine( "n4", "f4", colorFrustum ); + + // cone + + addLine( "p", "n1", colorCone ); + addLine( "p", "n2", colorCone ); + addLine( "p", "n3", colorCone ); + addLine( "p", "n4", colorCone ); + + // up + + addLine( "u1", "u2", colorUp ); + addLine( "u2", "u3", colorUp ); + addLine( "u3", "u1", colorUp ); + + // target + + addLine( "c", "t", colorTarget ); + addLine( "p", "c", colorCross ); + + // cross + + addLine( "cn1", "cn2", colorCross ); + addLine( "cn3", "cn4", colorCross ); + + addLine( "cf1", "cf2", colorCross ); + addLine( "cf3", "cf4", colorCross ); + + function addLine( a, b, color ) { + + addPoint( a, color ); + addPoint( b, color ); + + } + + function addPoint( id, color ) { + + vertices.push( 0, 0, 0 ); + colors.push( color.r, color.g, color.b ); + + if ( pointMap[ id ] === undefined ) { + + pointMap[ id ] = []; + + } + + pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); + + } + + geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + + LineSegments.call( this, geometry, material ); + + this.camera = camera; + if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix(); + + this.matrix = camera.matrixWorld; + this.matrixAutoUpdate = false; + + this.pointMap = pointMap; + + this.update(); + +} + +CameraHelper.prototype = Object.create( LineSegments.prototype ); +CameraHelper.prototype.constructor = CameraHelper; + +CameraHelper.prototype.update = function () { + + var geometry, pointMap; + + var vector = new Vector3(); + var camera = new Camera(); + + function setPoint( point, x, y, z ) { + + vector.set( x, y, z ).unproject( camera ); + + var points = pointMap[ point ]; + + if ( points !== undefined ) { + + var position = geometry.getAttribute( 'position' ); + + for ( var i = 0, l = points.length; i < l; i ++ ) { + + position.setXYZ( points[ i ], vector.x, vector.y, vector.z ); + + } + + } + + } + + return function update() { + + geometry = this.geometry; + pointMap = this.pointMap; + + var w = 1, h = 1; + + // we need just camera projection matrix + // world matrix must be identity + + camera.projectionMatrix.copy( this.camera.projectionMatrix ); + + // center / target + + setPoint( "c", 0, 0, - 1 ); + setPoint( "t", 0, 0, 1 ); + + // near + + setPoint( "n1", - w, - h, - 1 ); + setPoint( "n2", w, - h, - 1 ); + setPoint( "n3", - w, h, - 1 ); + setPoint( "n4", w, h, - 1 ); + + // far + + setPoint( "f1", - w, - h, 1 ); + setPoint( "f2", w, - h, 1 ); + setPoint( "f3", - w, h, 1 ); + setPoint( "f4", w, h, 1 ); + + // up + + setPoint( "u1", w * 0.7, h * 1.1, - 1 ); + setPoint( "u2", - w * 0.7, h * 1.1, - 1 ); + setPoint( "u3", 0, h * 2, - 1 ); + + // cross + + setPoint( "cf1", - w, 0, 1 ); + setPoint( "cf2", w, 0, 1 ); + setPoint( "cf3", 0, - h, 1 ); + setPoint( "cf4", 0, h, 1 ); + + setPoint( "cn1", - w, 0, - 1 ); + setPoint( "cn2", w, 0, - 1 ); + setPoint( "cn3", 0, - h, - 1 ); + setPoint( "cn4", 0, h, - 1 ); + + geometry.getAttribute( 'position' ).needsUpdate = true; + + }; + +}(); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function BoxHelper( object, color ) { + + if ( color === undefined ) color = 0xffff00; + + var indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); + var positions = new Float32Array( 8 * 3 ); + + var geometry = new BufferGeometry(); + geometry.setIndex( new BufferAttribute( indices, 1 ) ); + geometry.addAttribute( 'position', new BufferAttribute( positions, 3 ) ); + + LineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) ); + + if ( object !== undefined ) { + + this.update( object ); + + } + +} + +BoxHelper.prototype = Object.create( LineSegments.prototype ); +BoxHelper.prototype.constructor = BoxHelper; + +BoxHelper.prototype.update = ( function () { + + var box = new Box3(); + + return function update( object ) { + + if ( object && object.isBox3 ) { + + box.copy( object ); + + } else { + + box.setFromObject( object ); + + } + + if ( box.isEmpty() ) return; + + var min = box.min; + var max = box.max; + + /* + 5____4 + 1/___0/| + | 6__|_7 + 2/___3/ + + 0: max.x, max.y, max.z + 1: min.x, max.y, max.z + 2: min.x, min.y, max.z + 3: max.x, min.y, max.z + 4: max.x, max.y, min.z + 5: min.x, max.y, min.z + 6: min.x, min.y, min.z + 7: max.x, min.y, min.z + */ + + var position = this.geometry.attributes.position; + var array = position.array; + + array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z; + array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z; + array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z; + array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z; + array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z; + array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z; + array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z; + array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z; + + position.needsUpdate = true; + + this.geometry.computeBoundingSphere(); + + }; + +} )(); + +/** + * @author WestLangley / http://github.com/WestLangley + * @author zz85 / http://github.com/zz85 + * @author bhouston / http://clara.io + * + * Creates an arrow for visualizing directions + * + * Parameters: + * dir - Vector3 + * origin - Vector3 + * length - Number + * color - color in hex value + * headLength - Number + * headWidth - Number + */ + +var lineGeometry; +var coneGeometry; + +function ArrowHelper( dir, origin, length, color, headLength, headWidth ) { + + // dir is assumed to be normalized + + Object3D.call( this ); + + if ( color === undefined ) color = 0xffff00; + if ( length === undefined ) length = 1; + if ( headLength === undefined ) headLength = 0.2 * length; + if ( headWidth === undefined ) headWidth = 0.2 * headLength; + + if ( lineGeometry === undefined ) { + + lineGeometry = new BufferGeometry(); + lineGeometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); + + coneGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 ); + coneGeometry.translate( 0, - 0.5, 0 ); + + } + + this.position.copy( origin ); + + this.line = new Line( lineGeometry, new LineBasicMaterial( { color: color } ) ); + this.line.matrixAutoUpdate = false; + this.add( this.line ); + + this.cone = new Mesh( coneGeometry, new MeshBasicMaterial( { color: color } ) ); + this.cone.matrixAutoUpdate = false; + this.add( this.cone ); + + this.setDirection( dir ); + this.setLength( length, headLength, headWidth ); + +} + +ArrowHelper.prototype = Object.create( Object3D.prototype ); +ArrowHelper.prototype.constructor = ArrowHelper; + +ArrowHelper.prototype.setDirection = ( function () { + + var axis = new Vector3(); + var radians; + + return function setDirection( dir ) { + + // dir is assumed to be normalized + + if ( dir.y > 0.99999 ) { + + this.quaternion.set( 0, 0, 0, 1 ); + + } else if ( dir.y < - 0.99999 ) { + + this.quaternion.set( 1, 0, 0, 0 ); + + } else { + + axis.set( dir.z, 0, - dir.x ).normalize(); + + radians = Math.acos( dir.y ); + + this.quaternion.setFromAxisAngle( axis, radians ); + + } + + }; + +}() ); + +ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) { + + if ( headLength === undefined ) headLength = 0.2 * length; + if ( headWidth === undefined ) headWidth = 0.2 * headLength; + + this.line.scale.set( 1, Math.max( 0, length - headLength ), 1 ); + this.line.updateMatrix(); + + this.cone.scale.set( headWidth, headLength, headWidth ); + this.cone.position.y = length; + this.cone.updateMatrix(); + +}; + +ArrowHelper.prototype.setColor = function ( color ) { + + this.line.material.color.copy( color ); + this.cone.material.color.copy( color ); + +}; + +/** + * @author sroucheray / http://sroucheray.org/ + * @author mrdoob / http://mrdoob.com/ + */ + +function AxisHelper( size ) { + + size = size || 1; + + var vertices = [ + 0, 0, 0, size, 0, 0, + 0, 0, 0, 0, size, 0, + 0, 0, 0, 0, 0, size + ]; + + var colors = [ + 1, 0, 0, 1, 0.6, 0, + 0, 1, 0, 0.6, 1, 0, + 0, 0, 1, 0, 0.6, 1 + ]; + + var geometry = new BufferGeometry(); + geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + + var material = new LineBasicMaterial( { vertexColors: VertexColors } ); + + LineSegments.call( this, geometry, material ); + +} + +AxisHelper.prototype = Object.create( LineSegments.prototype ); +AxisHelper.prototype.constructor = AxisHelper; + +/** + * @author zz85 https://github.com/zz85 + * + * Centripetal CatmullRom Curve - which is useful for avoiding + * cusps and self-intersections in non-uniform catmull rom curves. + * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf + * + * curve.type accepts centripetal(default), chordal and catmullrom + * curve.tension is used for catmullrom which defaults to 0.5 + */ + + +/* +Based on an optimized c++ solution in + - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ + - http://ideone.com/NoEbVM + +This CubicPoly class could be used for reusing some variables and calculations, +but for three.js curve use, it could be possible inlined and flatten into a single function call +which can be placed in CurveUtils. +*/ + +function CubicPoly() { + + var c0 = 0, c1 = 0, c2 = 0, c3 = 0; + + /* + * Compute coefficients for a cubic polynomial + * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 + * such that + * p(0) = x0, p(1) = x1 + * and + * p'(0) = t0, p'(1) = t1. + */ + function init( x0, x1, t0, t1 ) { + + c0 = x0; + c1 = t0; + c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; + c3 = 2 * x0 - 2 * x1 + t0 + t1; + + } + + return { + + initCatmullRom: function ( x0, x1, x2, x3, tension ) { + + init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); + + }, + + initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { + + // compute tangents when parameterized in [t1,t2] + var t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; + var t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; + + // rescale tangents for parametrization in [0,1] + t1 *= dt1; + t2 *= dt1; + + init( x1, x2, t1, t2 ); + + }, + + calc: function ( t ) { + + var t2 = t * t; + var t3 = t2 * t; + return c0 + c1 * t + c2 * t2 + c3 * t3; + + } + + }; + +} + +// + +var tmp = new Vector3(); +var px = new CubicPoly(); +var py = new CubicPoly(); +var pz = new CubicPoly(); + +function CatmullRomCurve3( p /* array of Vector3 */ ) { + + this.points = p || []; + this.closed = false; + +} + +CatmullRomCurve3.prototype = Object.create( Curve.prototype ); +CatmullRomCurve3.prototype.constructor = CatmullRomCurve3; + +CatmullRomCurve3.prototype.getPoint = function ( t ) { + + var points = this.points; + var l = points.length; + + if ( l < 2 ) console.log( 'duh, you need at least 2 points' ); + + var point = ( l - ( this.closed ? 0 : 1 ) ) * t; + var intPoint = Math.floor( point ); + var weight = point - intPoint; + + if ( this.closed ) { + + intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; + + } else if ( weight === 0 && intPoint === l - 1 ) { + + intPoint = l - 2; + weight = 1; + + } + + var p0, p1, p2, p3; // 4 points + + if ( this.closed || intPoint > 0 ) { + + p0 = points[ ( intPoint - 1 ) % l ]; + + } else { + + // extrapolate first point + tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); + p0 = tmp; + + } + + p1 = points[ intPoint % l ]; + p2 = points[ ( intPoint + 1 ) % l ]; + + if ( this.closed || intPoint + 2 < l ) { + + p3 = points[ ( intPoint + 2 ) % l ]; + + } else { + + // extrapolate last point + tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); + p3 = tmp; + + } + + if ( this.type === undefined || this.type === 'centripetal' || this.type === 'chordal' ) { + + // init Centripetal / Chordal Catmull-Rom + var pow = this.type === 'chordal' ? 0.5 : 0.25; + var dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); + var dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); + var dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); + + // safety check for repeated points + if ( dt1 < 1e-4 ) dt1 = 1.0; + if ( dt0 < 1e-4 ) dt0 = dt1; + if ( dt2 < 1e-4 ) dt2 = dt1; + + px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); + py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); + pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); + + } else if ( this.type === 'catmullrom' ) { + + var tension = this.tension !== undefined ? this.tension : 0.5; + px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, tension ); + py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, tension ); + pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, tension ); + + } + + return new Vector3( px.calc( weight ), py.calc( weight ), pz.calc( weight ) ); + +}; + +function CubicBezierCurve3( v0, v1, v2, v3 ) { + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + +} + +CubicBezierCurve3.prototype = Object.create( Curve.prototype ); +CubicBezierCurve3.prototype.constructor = CubicBezierCurve3; + +CubicBezierCurve3.prototype.getPoint = function ( t ) { + + var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; + + return new Vector3( + CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), + CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), + CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) + ); + +}; + +function QuadraticBezierCurve3( v0, v1, v2 ) { + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + +} + +QuadraticBezierCurve3.prototype = Object.create( Curve.prototype ); +QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3; + +QuadraticBezierCurve3.prototype.getPoint = function ( t ) { + + var v0 = this.v0, v1 = this.v1, v2 = this.v2; + + return new Vector3( + QuadraticBezier( t, v0.x, v1.x, v2.x ), + QuadraticBezier( t, v0.y, v1.y, v2.y ), + QuadraticBezier( t, v0.z, v1.z, v2.z ) + ); + +}; + +function LineCurve3( v1, v2 ) { + + this.v1 = v1; + this.v2 = v2; + +} + +LineCurve3.prototype = Object.create( Curve.prototype ); +LineCurve3.prototype.constructor = LineCurve3; + +LineCurve3.prototype.getPoint = function ( t ) { + + if ( t === 1 ) { + + return this.v2.clone(); + + } + + var vector = new Vector3(); + + vector.subVectors( this.v2, this.v1 ); // diff + vector.multiplyScalar( t ); + vector.add( this.v1 ); + + return vector; + +}; + +function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + + EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); + +} + +ArcCurve.prototype = Object.create( EllipseCurve.prototype ); +ArcCurve.prototype.constructor = ArcCurve; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +var SceneUtils = { + + createMultiMaterialObject: function ( geometry, materials ) { + + var group = new Group(); + + for ( var i = 0, l = materials.length; i < l; i ++ ) { + + group.add( new Mesh( geometry, materials[ i ] ) ); + + } + + return group; + + }, + + detach: function ( child, parent, scene ) { + + child.applyMatrix( parent.matrixWorld ); + parent.remove( child ); + scene.add( child ); + + }, + + attach: function ( child, scene, parent ) { + + var matrixWorldInverse = new Matrix4(); + matrixWorldInverse.getInverse( parent.matrixWorld ); + child.applyMatrix( matrixWorldInverse ); + + scene.remove( child ); + parent.add( child ); + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function Face4( a, b, c, d, normal, color, materialIndex ) { + + console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' ); + return new Face3( a, b, c, normal, color, materialIndex ); + +} + +var LineStrip = 0; + +var LinePieces = 1; + +function MeshFaceMaterial( materials ) { + + console.warn( 'THREE.MeshFaceMaterial has been renamed to THREE.MultiMaterial.' ); + return new MultiMaterial( materials ); + +} + +function PointCloud( geometry, material ) { + + console.warn( 'THREE.PointCloud has been renamed to THREE.Points.' ); + return new Points( geometry, material ); + +} + +function Particle( material ) { + + console.warn( 'THREE.Particle has been renamed to THREE.Sprite.' ); + return new Sprite( material ); + +} + +function ParticleSystem( geometry, material ) { + + console.warn( 'THREE.ParticleSystem has been renamed to THREE.Points.' ); + return new Points( geometry, material ); + +} + +function PointCloudMaterial( parameters ) { + + console.warn( 'THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.' ); + return new PointsMaterial( parameters ); + +} + +function ParticleBasicMaterial( parameters ) { + + console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.' ); + return new PointsMaterial( parameters ); + +} + +function ParticleSystemMaterial( parameters ) { + + console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.' ); + return new PointsMaterial( parameters ); + +} + +function Vertex( x, y, z ) { + + console.warn( 'THREE.Vertex has been removed. Use THREE.Vector3 instead.' ); + return new Vector3( x, y, z ); + +} + +// + +function DynamicBufferAttribute( array, itemSize ) { + + console.warn( 'THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setDynamic( true ) instead.' ); + return new BufferAttribute( array, itemSize ).setDynamic( true ); + +} + +function Int8Attribute( array, itemSize ) { + + console.warn( 'THREE.Int8Attribute has been removed. Use new THREE.Int8BufferAttribute() instead.' ); + return new Int8BufferAttribute( array, itemSize ); + +} + +function Uint8Attribute( array, itemSize ) { + + console.warn( 'THREE.Uint8Attribute has been removed. Use new THREE.Uint8BufferAttribute() instead.' ); + return new Uint8BufferAttribute( array, itemSize ); + +} + +function Uint8ClampedAttribute( array, itemSize ) { + + console.warn( 'THREE.Uint8ClampedAttribute has been removed. Use new THREE.Uint8ClampedBufferAttribute() instead.' ); + return new Uint8ClampedBufferAttribute( array, itemSize ); + +} + +function Int16Attribute( array, itemSize ) { + + console.warn( 'THREE.Int16Attribute has been removed. Use new THREE.Int16BufferAttribute() instead.' ); + return new Int16BufferAttribute( array, itemSize ); + +} + +function Uint16Attribute( array, itemSize ) { + + console.warn( 'THREE.Uint16Attribute has been removed. Use new THREE.Uint16BufferAttribute() instead.' ); + return new Uint16BufferAttribute( array, itemSize ); + +} + +function Int32Attribute( array, itemSize ) { + + console.warn( 'THREE.Int32Attribute has been removed. Use new THREE.Int32BufferAttribute() instead.' ); + return new Int32BufferAttribute( array, itemSize ); + +} + +function Uint32Attribute( array, itemSize ) { + + console.warn( 'THREE.Uint32Attribute has been removed. Use new THREE.Uint32BufferAttribute() instead.' ); + return new Uint32BufferAttribute( array, itemSize ); + +} + +function Float32Attribute( array, itemSize ) { + + console.warn( 'THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead.' ); + return new Float32BufferAttribute( array, itemSize ); + +} + +function Float64Attribute( array, itemSize ) { + + console.warn( 'THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead.' ); + return new Float64BufferAttribute( array, itemSize ); + +} + +// + +Curve.create = function ( construct, getPoint ) { + + console.log( 'THREE.Curve.create() has been deprecated' ); + + construct.prototype = Object.create( Curve.prototype ); + construct.prototype.constructor = construct; + construct.prototype.getPoint = getPoint; + + return construct; + +}; + +// + +function ClosedSplineCurve3( points ) { + + console.warn( 'THREE.ClosedSplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' ); + + CatmullRomCurve3.call( this, points ); + this.type = 'catmullrom'; + this.closed = true; + +} + +ClosedSplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype ); + +// + +function SplineCurve3( points ) { + + console.warn( 'THREE.SplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' ); + + CatmullRomCurve3.call( this, points ); + this.type = 'catmullrom'; + +} + +SplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype ); + +// + +function Spline( points ) { + + console.warn( 'THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.' ); + + CatmullRomCurve3.call( this, points ); + this.type = 'catmullrom'; + +} + +Spline.prototype = Object.create( CatmullRomCurve3.prototype ); + +Object.assign( Spline.prototype, { + + initFromArray: function ( a ) { + + console.error( 'THREE.Spline: .initFromArray() has been removed.' ); + + }, + getControlPointsArray: function ( optionalTarget ) { + + console.error( 'THREE.Spline: .getControlPointsArray() has been removed.' ); + + }, + reparametrizeByArcLength: function ( samplingCoef ) { + + console.error( 'THREE.Spline: .reparametrizeByArcLength() has been removed.' ); + + } + +} ); + +// +function BoundingBoxHelper( object, color ) { + + console.warn( 'THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead.' ); + return new BoxHelper( object, color ); + +} + +function EdgesHelper( object, hex ) { + + console.warn( 'THREE.EdgesHelper has been removed. Use THREE.EdgesGeometry instead.' ); + return new LineSegments( new EdgesGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) ); + +} + +GridHelper.prototype.setColors = function () { + + console.error( 'THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.' ); + +}; + +function WireframeHelper( object, hex ) { + + console.warn( 'THREE.WireframeHelper has been removed. Use THREE.WireframeGeometry instead.' ); + return new LineSegments( new WireframeGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) ); + +} + +// + +function XHRLoader( manager ) { + + console.warn( 'THREE.XHRLoader has been renamed to THREE.FileLoader.' ); + return new FileLoader( manager ); + +} + +function BinaryTextureLoader( manager ) { + + console.warn( 'THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader.' ); + return new DataTextureLoader( manager ); + +} + +// + +Object.assign( Box2.prototype, { + + center: function ( optionalTarget ) { + + console.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' ); + return this.getCenter( optionalTarget ); + + }, + empty: function () { + + console.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' ); + return this.isEmpty(); + + }, + isIntersectionBox: function ( box ) { + + console.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' ); + return this.intersectsBox( box ); + + }, + size: function ( optionalTarget ) { + + console.warn( 'THREE.Box2: .size() has been renamed to .getSize().' ); + return this.getSize( optionalTarget ); + + } +} ); + +Object.assign( Box3.prototype, { + + center: function ( optionalTarget ) { + + console.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' ); + return this.getCenter( optionalTarget ); + + }, + empty: function () { + + console.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' ); + return this.isEmpty(); + + }, + isIntersectionBox: function ( box ) { + + console.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' ); + return this.intersectsBox( box ); + + }, + isIntersectionSphere: function ( sphere ) { + + console.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' ); + return this.intersectsSphere( sphere ); + + }, + size: function ( optionalTarget ) { + + console.warn( 'THREE.Box3: .size() has been renamed to .getSize().' ); + return this.getSize( optionalTarget ); + + } +} ); + +Line3.prototype.center = function ( optionalTarget ) { + + console.warn( 'THREE.Line3: .center() has been renamed to .getCenter().' ); + return this.getCenter( optionalTarget ); + +}; + +_Math.random16 = function () { + + console.warn( 'THREE.Math.random16() has been deprecated. Use Math.random() instead.' ); + return Math.random(); + +}; + +Object.assign( Matrix3.prototype, { + + flattenToArrayOffset: function ( array, offset ) { + + console.warn( "THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." ); + return this.toArray( array, offset ); + + }, + multiplyVector3: function ( vector ) { + + console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); + return vector.applyMatrix3( this ); + + }, + multiplyVector3Array: function ( a ) { + + console.warn( 'THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); + return this.applyToVector3Array( a ); + + }, + applyToBuffer: function( buffer, offset, length ) { + + console.warn( 'THREE.Matrix3: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' ); + return this.applyToBufferAttribute( buffer ); + + }, + applyToVector3Array: function( array, offset, length ) { + + console.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' ); + + } + +} ); + +Object.assign( Matrix4.prototype, { + + extractPosition: function ( m ) { + + console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' ); + return this.copyPosition( m ); + + }, + flattenToArrayOffset: function ( array, offset ) { + + console.warn( "THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." ); + return this.toArray( array, offset ); + + }, + getPosition: function () { + + var v1; + + return function getPosition() { + + if ( v1 === undefined ) v1 = new Vector3(); + console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); + return v1.setFromMatrixColumn( this, 3 ); + + }; + + }(), + setRotationFromQuaternion: function ( q ) { + + console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); + return this.makeRotationFromQuaternion( q ); + + }, + multiplyVector3: function ( vector ) { + + console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); + + }, + multiplyVector4: function ( vector ) { + + console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); + + }, + multiplyVector3Array: function ( a ) { + + console.warn( 'THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); + return this.applyToVector3Array( a ); + + }, + rotateAxis: function ( v ) { + + console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); + v.transformDirection( this ); + + }, + crossVector: function ( vector ) { + + console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); + + }, + translate: function () { + + console.error( 'THREE.Matrix4: .translate() has been removed.' ); + + }, + rotateX: function () { + + console.error( 'THREE.Matrix4: .rotateX() has been removed.' ); + + }, + rotateY: function () { + + console.error( 'THREE.Matrix4: .rotateY() has been removed.' ); + + }, + rotateZ: function () { + + console.error( 'THREE.Matrix4: .rotateZ() has been removed.' ); + + }, + rotateByAxis: function () { + + console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' ); + + }, + applyToBuffer: function( buffer, offset, length ) { + + console.warn( 'THREE.Matrix4: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' ); + return this.applyToBufferAttribute( buffer ); + + }, + applyToVector3Array: function( array, offset, length ) { + + console.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' ); + + }, + makeFrustum: function( left, right, bottom, top, near, far ) { + + console.warn( 'THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead.' ); + return this.makePerspective( left, right, top, bottom, near, far ); + + } + +} ); + +Plane.prototype.isIntersectionLine = function ( line ) { + + console.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' ); + return this.intersectsLine( line ); + +}; + +Quaternion.prototype.multiplyVector3 = function ( vector ) { + + console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); + return vector.applyQuaternion( this ); + +}; + +Object.assign( Ray.prototype, { + + isIntersectionBox: function ( box ) { + + console.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' ); + return this.intersectsBox( box ); + + }, + isIntersectionPlane: function ( plane ) { + + console.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' ); + return this.intersectsPlane( plane ); + + }, + isIntersectionSphere: function ( sphere ) { + + console.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' ); + return this.intersectsSphere( sphere ); + + } + +} ); + +Object.assign( Shape.prototype, { + + extrude: function ( options ) { + + console.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' ); + return new ExtrudeGeometry( this, options ); + + }, + makeGeometry: function ( options ) { + + console.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' ); + return new ShapeGeometry( this, options ); + + } + +} ); + +Object.assign( Vector2.prototype, { + + fromAttribute: function ( attribute, index, offset ) { + + console.error( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' ); + return this.fromBufferAttribute( attribute, index, offset ); + + } + +} ); + +Object.assign( Vector3.prototype, { + + setEulerFromRotationMatrix: function () { + + console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' ); + + }, + setEulerFromQuaternion: function () { + + console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' ); + + }, + getPositionFromMatrix: function ( m ) { + + console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' ); + return this.setFromMatrixPosition( m ); + + }, + getScaleFromMatrix: function ( m ) { + + console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' ); + return this.setFromMatrixScale( m ); + + }, + getColumnFromMatrix: function ( index, matrix ) { + + console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' ); + return this.setFromMatrixColumn( matrix, index ); + + }, + applyProjection: function ( m ) { + + console.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' ); + return this.applyMatrix4( m ); + + }, + fromAttribute: function ( attribute, index, offset ) { + + console.error( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' ); + return this.fromBufferAttribute( attribute, index, offset ); + + } + +} ); + +Object.assign( Vector4.prototype, { + + fromAttribute: function ( attribute, index, offset ) { + + console.error( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' ); + return this.fromBufferAttribute( attribute, index, offset ); + + } + +} ); + +// + +Geometry.prototype.computeTangents = function () { + + console.warn( 'THREE.Geometry: .computeTangents() has been removed.' ); + +}; + +Object.assign( Object3D.prototype, { + + getChildByName: function ( name ) { + + console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' ); + return this.getObjectByName( name ); + + }, + renderDepth: function () { + + console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' ); + + }, + translate: function ( distance, axis ) { + + console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' ); + return this.translateOnAxis( axis, distance ); + + } + +} ); + +Object.defineProperties( Object3D.prototype, { + + eulerOrder: { + get: function () { + + console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' ); + return this.rotation.order; + + }, + set: function ( value ) { + + console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' ); + this.rotation.order = value; + + } + }, + useQuaternion: { + get: function () { + + console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); + + }, + set: function () { + + console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); + + } + } + +} ); + +Object.defineProperties( LOD.prototype, { + + objects: { + get: function () { + + console.warn( 'THREE.LOD: .objects has been renamed to .levels.' ); + return this.levels; + + } + } + +} ); + +// + +PerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) { + + console.warn( "THREE.PerspectiveCamera.setLens is deprecated. " + + "Use .setFocalLength and .filmGauge for a photographic setup." ); + + if ( filmGauge !== undefined ) this.filmGauge = filmGauge; + this.setFocalLength( focalLength ); + +}; + +// + +Object.defineProperties( Light.prototype, { + onlyShadow: { + set: function () { + + console.warn( 'THREE.Light: .onlyShadow has been removed.' ); + + } + }, + shadowCameraFov: { + set: function ( value ) { + + console.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' ); + this.shadow.camera.fov = value; + + } + }, + shadowCameraLeft: { + set: function ( value ) { + + console.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' ); + this.shadow.camera.left = value; + + } + }, + shadowCameraRight: { + set: function ( value ) { + + console.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' ); + this.shadow.camera.right = value; + + } + }, + shadowCameraTop: { + set: function ( value ) { + + console.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' ); + this.shadow.camera.top = value; + + } + }, + shadowCameraBottom: { + set: function ( value ) { + + console.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' ); + this.shadow.camera.bottom = value; + + } + }, + shadowCameraNear: { + set: function ( value ) { + + console.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' ); + this.shadow.camera.near = value; + + } + }, + shadowCameraFar: { + set: function ( value ) { + + console.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' ); + this.shadow.camera.far = value; + + } + }, + shadowCameraVisible: { + set: function () { + + console.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' ); + + } + }, + shadowBias: { + set: function ( value ) { + + console.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' ); + this.shadow.bias = value; + + } + }, + shadowDarkness: { + set: function () { + + console.warn( 'THREE.Light: .shadowDarkness has been removed.' ); + + } + }, + shadowMapWidth: { + set: function ( value ) { + + console.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' ); + this.shadow.mapSize.width = value; + + } + }, + shadowMapHeight: { + set: function ( value ) { + + console.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' ); + this.shadow.mapSize.height = value; + + } + } +} ); + +// + +Object.defineProperties( BufferAttribute.prototype, { + + length: { + get: function () { + + console.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' ); + return this.array.length; + + } + } + +} ); + +Object.assign( BufferGeometry.prototype, { + + addIndex: function ( index ) { + + console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' ); + this.setIndex( index ); + + }, + addDrawCall: function ( start, count, indexOffset ) { + + if ( indexOffset !== undefined ) { + + console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' ); + + } + console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' ); + this.addGroup( start, count ); + + }, + clearDrawCalls: function () { + + console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' ); + this.clearGroups(); + + }, + computeTangents: function () { + + console.warn( 'THREE.BufferGeometry: .computeTangents() has been removed.' ); + + }, + computeOffsets: function () { + + console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' ); + + } + +} ); + +Object.defineProperties( BufferGeometry.prototype, { + + drawcalls: { + get: function () { + + console.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' ); + return this.groups; + + } + }, + offsets: { + get: function () { + + console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' ); + return this.groups; + + } + } + +} ); + +// + +Object.defineProperties( Uniform.prototype, { + + dynamic: { + set: function () { + + console.warn( 'THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.' ); + + } + }, + onUpdate: { + value: function () { + + console.warn( 'THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.' ); + return this; + + } + } + +} ); + +// + +Object.defineProperties( Material.prototype, { + + wrapAround: { + get: function () { + + console.warn( 'THREE.' + this.type + ': .wrapAround has been removed.' ); + + }, + set: function () { + + console.warn( 'THREE.' + this.type + ': .wrapAround has been removed.' ); + + } + }, + wrapRGB: { + get: function () { + + console.warn( 'THREE.' + this.type + ': .wrapRGB has been removed.' ); + return new Color(); + + } + } + +} ); + +Object.defineProperties( MeshPhongMaterial.prototype, { + + metal: { + get: function () { + + console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.' ); + return false; + + }, + set: function () { + + console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead' ); + + } + } + +} ); + +Object.defineProperties( ShaderMaterial.prototype, { + + derivatives: { + get: function () { + + console.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' ); + return this.extensions.derivatives; + + }, + set: function ( value ) { + + console.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' ); + this.extensions.derivatives = value; + + } + } + +} ); + +// + +Object.assign( WebGLRenderer.prototype, { + + supportsFloatTextures: function () { + + console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' ); + return this.extensions.get( 'OES_texture_float' ); + + }, + supportsHalfFloatTextures: function () { + + console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' ); + return this.extensions.get( 'OES_texture_half_float' ); + + }, + supportsStandardDerivatives: function () { + + console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' ); + return this.extensions.get( 'OES_standard_derivatives' ); + + }, + supportsCompressedTextureS3TC: function () { + + console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' ); + return this.extensions.get( 'WEBGL_compressed_texture_s3tc' ); + + }, + supportsCompressedTexturePVRTC: function () { + + console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' ); + return this.extensions.get( 'WEBGL_compressed_texture_pvrtc' ); + + }, + supportsBlendMinMax: function () { + + console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' ); + return this.extensions.get( 'EXT_blend_minmax' ); + + }, + supportsVertexTextures: function () { + + console.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' ); + return this.capabilities.vertexTextures; + + }, + supportsInstancedArrays: function () { + + console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' ); + return this.extensions.get( 'ANGLE_instanced_arrays' ); + + }, + enableScissorTest: function ( boolean ) { + + console.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' ); + this.setScissorTest( boolean ); + + }, + initMaterial: function () { + + console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); + + }, + addPrePlugin: function () { + + console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); + + }, + addPostPlugin: function () { + + console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); + + }, + updateShadowMap: function () { + + console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); + + } + +} ); + +Object.defineProperties( WebGLRenderer.prototype, { + + shadowMapEnabled: { + get: function () { + + return this.shadowMap.enabled; + + }, + set: function ( value ) { + + console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' ); + this.shadowMap.enabled = value; + + } + }, + shadowMapType: { + get: function () { + + return this.shadowMap.type; + + }, + set: function ( value ) { + + console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' ); + this.shadowMap.type = value; + + } + }, + shadowMapCullFace: { + get: function () { + + return this.shadowMap.cullFace; + + }, + set: function ( value ) { + + console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace is now .shadowMap.cullFace.' ); + this.shadowMap.cullFace = value; + + } + } +} ); + +Object.defineProperties( WebGLShadowMap.prototype, { + + cullFace: { + get: function () { + + return this.renderReverseSided ? CullFaceFront : CullFaceBack; + + }, + set: function ( cullFace ) { + + var value = ( cullFace !== CullFaceBack ); + console.warn( "WebGLRenderer: .shadowMap.cullFace is deprecated. Set .shadowMap.renderReverseSided to " + value + "." ); + this.renderReverseSided = value; + + } + } + +} ); + +// + +Object.defineProperties( WebGLRenderTarget.prototype, { + + wrapS: { + get: function () { + + console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' ); + return this.texture.wrapS; + + }, + set: function ( value ) { + + console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' ); + this.texture.wrapS = value; + + } + }, + wrapT: { + get: function () { + + console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' ); + return this.texture.wrapT; + + }, + set: function ( value ) { + + console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' ); + this.texture.wrapT = value; + + } + }, + magFilter: { + get: function () { + + console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' ); + return this.texture.magFilter; + + }, + set: function ( value ) { + + console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' ); + this.texture.magFilter = value; + + } + }, + minFilter: { + get: function () { + + console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' ); + return this.texture.minFilter; + + }, + set: function ( value ) { + + console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' ); + this.texture.minFilter = value; + + } + }, + anisotropy: { + get: function () { + + console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' ); + return this.texture.anisotropy; + + }, + set: function ( value ) { + + console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' ); + this.texture.anisotropy = value; + + } + }, + offset: { + get: function () { + + console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' ); + return this.texture.offset; + + }, + set: function ( value ) { + + console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' ); + this.texture.offset = value; + + } + }, + repeat: { + get: function () { + + console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' ); + return this.texture.repeat; + + }, + set: function ( value ) { + + console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' ); + this.texture.repeat = value; + + } + }, + format: { + get: function () { + + console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' ); + return this.texture.format; + + }, + set: function ( value ) { + + console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' ); + this.texture.format = value; + + } + }, + type: { + get: function () { + + console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' ); + return this.texture.type; + + }, + set: function ( value ) { + + console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' ); + this.texture.type = value; + + } + }, + generateMipmaps: { + get: function () { + + console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' ); + return this.texture.generateMipmaps; + + }, + set: function ( value ) { + + console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' ); + this.texture.generateMipmaps = value; + + } + } + +} ); + +// + +Audio.prototype.load = function ( file ) { + + console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' ); + var scope = this; + var audioLoader = new AudioLoader(); + audioLoader.load( file, function ( buffer ) { + + scope.setBuffer( buffer ); + + } ); + return this; + +}; + +AudioAnalyser.prototype.getData = function () { + + console.warn( 'THREE.AudioAnalyser: .getData() is now .getFrequencyData().' ); + return this.getFrequencyData(); + +}; + +// + +var GeometryUtils = { + + merge: function ( geometry1, geometry2, materialIndexOffset ) { + + console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' ); + var matrix; + + if ( geometry2.isMesh ) { + + geometry2.matrixAutoUpdate && geometry2.updateMatrix(); + + matrix = geometry2.matrix; + geometry2 = geometry2.geometry; + + } + + geometry1.merge( geometry2, matrix, materialIndexOffset ); + + }, + + center: function ( geometry ) { + + console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' ); + return geometry.center(); + + } + +}; + +var ImageUtils = { + + crossOrigin: undefined, + + loadTexture: function ( url, mapping, onLoad, onError ) { + + console.warn( 'THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.' ); + + var loader = new TextureLoader(); + loader.setCrossOrigin( this.crossOrigin ); + + var texture = loader.load( url, onLoad, undefined, onError ); + + if ( mapping ) texture.mapping = mapping; + + return texture; + + }, + + loadTextureCube: function ( urls, mapping, onLoad, onError ) { + + console.warn( 'THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.' ); + + var loader = new CubeTextureLoader(); + loader.setCrossOrigin( this.crossOrigin ); + + var texture = loader.load( urls, onLoad, undefined, onError ); + + if ( mapping ) texture.mapping = mapping; + + return texture; + + }, + + loadCompressedTexture: function () { + + console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' ); + + }, + + loadCompressedTextureCube: function () { + + console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' ); + + } + +}; + +// + +function Projector() { + + console.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' ); + + this.projectVector = function ( vector, camera ) { + + console.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); + vector.project( camera ); + + }; + + this.unprojectVector = function ( vector, camera ) { + + console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); + vector.unproject( camera ); + + }; + + this.pickingRay = function () { + + console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); + + }; + +} + +// + +function CanvasRenderer() { + + console.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' ); + + this.domElement = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); + this.clear = function () {}; + this.render = function () {}; + this.setClearColor = function () {}; + this.setSize = function () {}; + +} + + + + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +module.exports = function(THREE) { + var CopyShader = EffectComposer.CopyShader = __webpack_require__(27) + , RenderPass = EffectComposer.RenderPass = __webpack_require__(30)(THREE) + , ShaderPass = EffectComposer.ShaderPass = __webpack_require__(31)(THREE, EffectComposer) + , MaskPass = EffectComposer.MaskPass = __webpack_require__(29)(THREE) + , ClearMaskPass = EffectComposer.ClearMaskPass = __webpack_require__(28)(THREE) + + function EffectComposer( renderer, renderTarget ) { + this.renderer = renderer; + + if ( renderTarget === undefined ) { + var width = window.innerWidth || 1; + var height = window.innerHeight || 1; + var parameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false }; + + renderTarget = new THREE.WebGLRenderTarget( width, height, parameters ); + } + + this.renderTarget1 = renderTarget; + this.renderTarget2 = renderTarget.clone(); + + this.writeBuffer = this.renderTarget1; + this.readBuffer = this.renderTarget2; + + this.passes = []; + + this.copyPass = new ShaderPass( CopyShader ); + }; + + EffectComposer.prototype = { + swapBuffers: function() { + + var tmp = this.readBuffer; + this.readBuffer = this.writeBuffer; + this.writeBuffer = tmp; + + }, + + addPass: function ( pass ) { + + this.passes.push( pass ); + + }, + + insertPass: function ( pass, index ) { + + this.passes.splice( index, 0, pass ); + + }, + + render: function ( delta ) { + + this.writeBuffer = this.renderTarget1; + this.readBuffer = this.renderTarget2; + + var maskActive = false; + + var pass, i, il = this.passes.length; + + for ( i = 0; i < il; i ++ ) { + + pass = this.passes[ i ]; + + if ( !pass.enabled ) continue; + + pass.render( this.renderer, this.writeBuffer, this.readBuffer, delta, maskActive ); + + if ( pass.needsSwap ) { + + if ( maskActive ) { + + var context = this.renderer.context; + + context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff ); + + this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, delta ); + + context.stencilFunc( context.EQUAL, 1, 0xffffffff ); + + } + + this.swapBuffers(); + + } + + if ( pass instanceof MaskPass ) { + + maskActive = true; + + } else if ( pass instanceof ClearMaskPass ) { + + maskActive = false; + + } + + } + + }, + + reset: function ( renderTarget ) { + + if ( renderTarget === undefined ) { + + renderTarget = this.renderTarget1.clone(); + + renderTarget.width = window.innerWidth; + renderTarget.height = window.innerHeight; + + } + + this.renderTarget1 = renderTarget; + this.renderTarget2 = renderTarget.clone(); + + this.writeBuffer = this.renderTarget1; + this.readBuffer = this.renderTarget2; + + }, + + setSize: function ( width, height ) { + + var renderTarget = this.renderTarget1.clone(); + + renderTarget.width = width; + renderTarget.height = height; + + this.reset( renderTarget ); + + } + + }; + + // shared ortho camera + + EffectComposer.camera = new THREE.OrthographicCamera( -1, 1, 1, -1, 0, 1 ); + + EffectComposer.quad = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), null ); + + EffectComposer.scene = new THREE.Scene(); + EffectComposer.scene.add( EffectComposer.quad ); + + return EffectComposer +}; + +/***/ }), +/* 2 */ +/***/ (function(module, exports) { + +module.exports = "\n// we use this vertex shader for the post process steps. All we do is copy the uv value and set position appropriately\nvarying vec2 f_uv;\nvoid main() {\n f_uv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}" + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +// this file is just for convenience. it sets up loading the mario obj and texture +// comment +var THREE = __webpack_require__(0); +__webpack_require__(5)(THREE); + +var textureLoaded = exports.textureLoaded = new Promise(function (resolve, reject) { + new THREE.TextureLoader().load(__webpack_require__(26), function (texture) { + resolve(texture); + }); +}); + +var objLoaded = exports.objLoaded = new Promise(function (resolve, reject) { + new THREE.OBJLoader().load(__webpack_require__(4), function (obj) { + var geo = obj.children[0].geometry; + geo.computeBoundingSphere(); + resolve(geo); + }); +}); + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports = __webpack_require__.p + "./assets/wahoo-d362db.obj"; + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = function (THREE) { + + /** + * @author mrdoob / http://mrdoob.com/ + */ + THREE.OBJLoader = function (manager) { + + this.manager = manager !== undefined ? manager : THREE.DefaultLoadingManager; + }; + + THREE.OBJLoader.prototype = { + + constructor: THREE.OBJLoader, + + load: function load(url, onLoad, onProgress, onError) { + + var scope = this; + + var loader = new THREE.XHRLoader(scope.manager); + loader.load(url, function (text) { + + onLoad(scope.parse(text)); + }, onProgress, onError); + }, + + parse: function parse(text) { + + console.time('OBJLoader'); + + var object, + objects = []; + var geometry, material; + + function parseVertexIndex(value) { + + var index = parseInt(value); + + return (index >= 0 ? index - 1 : index + vertices.length / 3) * 3; + } + + function parseNormalIndex(value) { + + var index = parseInt(value); + + return (index >= 0 ? index - 1 : index + normals.length / 3) * 3; + } + + function parseUVIndex(value) { + + var index = parseInt(value); + + return (index >= 0 ? index - 1 : index + uvs.length / 2) * 2; + } + + function addVertex(a, b, c) { + + geometry.vertices.push(vertices[a], vertices[a + 1], vertices[a + 2], vertices[b], vertices[b + 1], vertices[b + 2], vertices[c], vertices[c + 1], vertices[c + 2]); + } + + function addNormal(a, b, c) { + + geometry.normals.push(normals[a], normals[a + 1], normals[a + 2], normals[b], normals[b + 1], normals[b + 2], normals[c], normals[c + 1], normals[c + 2]); + } + + function addUV(a, b, c) { + + geometry.uvs.push(uvs[a], uvs[a + 1], uvs[b], uvs[b + 1], uvs[c], uvs[c + 1]); + } + + function addFace(a, b, c, d, ua, ub, uc, ud, na, nb, nc, nd) { + + var ia = parseVertexIndex(a); + var ib = parseVertexIndex(b); + var ic = parseVertexIndex(c); + var id; + + if (d === undefined) { + + addVertex(ia, ib, ic); + } else { + + id = parseVertexIndex(d); + + addVertex(ia, ib, id); + addVertex(ib, ic, id); + } + + if (ua !== undefined) { + + ia = parseUVIndex(ua); + ib = parseUVIndex(ub); + ic = parseUVIndex(uc); + + if (d === undefined) { + + addUV(ia, ib, ic); + } else { + + id = parseUVIndex(ud); + + addUV(ia, ib, id); + addUV(ib, ic, id); + } + } + + if (na !== undefined) { + + ia = parseNormalIndex(na); + ib = parseNormalIndex(nb); + ic = parseNormalIndex(nc); + + if (d === undefined) { + + addNormal(ia, ib, ic); + } else { + + id = parseNormalIndex(nd); + + addNormal(ia, ib, id); + addNormal(ib, ic, id); + } + } + } + + // create mesh if no objects in text + + if (/^o /gm.test(text) === false) { + + geometry = { + vertices: [], + normals: [], + uvs: [] + }; + + material = { + name: '' + }; + + object = { + name: '', + geometry: geometry, + material: material + }; + + objects.push(object); + } + + var vertices = []; + var normals = []; + var uvs = []; + + // v float float float + + var vertex_pattern = /v( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; + + // vn float float float + + var normal_pattern = /vn( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; + + // vt float float + + var uv_pattern = /vt( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; + + // f vertex vertex vertex ... + + var face_pattern1 = /f( +-?\d+)( +-?\d+)( +-?\d+)( +-?\d+)?/; + + // f vertex/uv vertex/uv vertex/uv ... + + var face_pattern2 = /f( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))?/; + + // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ... + + var face_pattern3 = /f( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))?/; + + // f vertex//normal vertex//normal vertex//normal ... + + var face_pattern4 = /f( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))?/; + + // + + var lines = text.split('\n'); + + for (var i = 0; i < lines.length; i++) { + + var line = lines[i]; + line = line.trim(); + + var result; + + if (line.length === 0 || line.charAt(0) === '#') { + + continue; + } else if ((result = vertex_pattern.exec(line)) !== null) { + + // ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"] + + vertices.push(parseFloat(result[1]), parseFloat(result[2]), parseFloat(result[3])); + } else if ((result = normal_pattern.exec(line)) !== null) { + + // ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"] + + normals.push(parseFloat(result[1]), parseFloat(result[2]), parseFloat(result[3])); + } else if ((result = uv_pattern.exec(line)) !== null) { + + // ["vt 0.1 0.2", "0.1", "0.2"] + + uvs.push(parseFloat(result[1]), parseFloat(result[2])); + } else if ((result = face_pattern1.exec(line)) !== null) { + + // ["f 1 2 3", "1", "2", "3", undefined] + + addFace(result[1], result[2], result[3], result[4]); + } else if ((result = face_pattern2.exec(line)) !== null) { + + // ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined] + + addFace(result[2], result[5], result[8], result[11], result[3], result[6], result[9], result[12]); + } else if ((result = face_pattern3.exec(line)) !== null) { + + // ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined] + + addFace(result[2], result[6], result[10], result[14], result[3], result[7], result[11], result[15], result[4], result[8], result[12], result[16]); + } else if ((result = face_pattern4.exec(line)) !== null) { + + // ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined] + + addFace(result[2], result[5], result[8], result[11], undefined, undefined, undefined, undefined, result[3], result[6], result[9], result[12]); + } else if (/^o /.test(line)) { + + geometry = { + vertices: [], + normals: [], + uvs: [] + }; + + material = { + name: '' + }; + + object = { + name: line.substring(2).trim(), + geometry: geometry, + material: material + }; + + objects.push(object); + } else if (/^g /.test(line)) { + + // group + + } else if (/^usemtl /.test(line)) { + + // material + + material.name = line.substring(7).trim(); + } else if (/^mtllib /.test(line)) { + + // mtl file + + } else if (/^s /.test(line)) { + + // smooth shading + + } else { + + // console.log( "THREE.OBJLoader: Unhandled line " + line ); + + } + } + + var container = new THREE.Object3D(); + var l; + + for (i = 0, l = objects.length; i < l; i++) { + + object = objects[i]; + geometry = object.geometry; + + var buffergeometry = new THREE.BufferGeometry(); + + buffergeometry.addAttribute('position', new THREE.BufferAttribute(new Float32Array(geometry.vertices), 3)); + + if (geometry.normals.length > 0) { + + buffergeometry.addAttribute('normal', new THREE.BufferAttribute(new Float32Array(geometry.normals), 3)); + } + + if (geometry.uvs.length > 0) { + + buffergeometry.addAttribute('uv', new THREE.BufferAttribute(new Float32Array(geometry.uvs), 2)); + } + + material = new THREE.MeshLambertMaterial({ + color: 0xff0000 + }); + material.name = object.material.name; + + var mesh = new THREE.Mesh(buffergeometry, material); + mesh.name = object.name; + + container.add(mesh); + } + + console.timeEnd('OBJLoader'); + + return container; + } + + }; +}; + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.setupGUI = setupGUI; + +var _shaders = __webpack_require__(18); + +var Shaders = _interopRequireWildcard(_shaders); + +var _post = __webpack_require__(13); + +var Post = _interopRequireWildcard(_post); + +var _datGui = __webpack_require__(22); + +var _datGui2 = _interopRequireDefault(_datGui); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +_datGui2.default.GUI.prototype.removeFolder = function (name) { + var folder = this.__folders[name]; + if (!folder) { + return; + } + folder.close(); + this.__ul.removeChild(folder.domElement.parentNode); + delete this.__folders[name]; + this.onResize(); +}; + +_datGui2.default.GUI.prototype.emptyFolder = function (name) { + var folder = this.__folders[name]; + if (!folder) { + return; + } + for (var i = 0; i < folder.__controllers.length; ++i) { + folder.__controllers[i].remove(); + } + folder.__controllers.length = 0; + this.onResize(); +}; + +function setupGUI(shaderSet, postProcessSet) { + var gui = new _datGui2.default.GUI(); + var opts = { shader: null, post: null }; + + var shaderControl = gui.add(opts, 'shader', Object.keys(Shaders)).onChange(function (name) { + setShader(name); + }); + var shaderFolder = gui.addFolder('Shader Settings'); + shaderFolder.open(); + + var postControl = gui.add(opts, 'post', Object.keys(Post)).onChange(function (name) { + setPostProcess(name); + }); + var postFolder = gui.addFolder('Post Process Settings'); + postFolder.open(); + + function setShader(name) { + gui.emptyFolder('Shader Settings'); + opts.shader = name; + shaderControl.updateDisplay(); + shaderSet(Shaders[name], shaderFolder); + } + + function setPostProcess(name) { + gui.emptyFolder('Post Process Settings'); + opts.post = name; + postControl.updateDisplay(); + postProcessSet(Post[name], postFolder); + } + + setShader(Object.keys(Shaders)[0]); + setPostProcess(Object.keys(Post)[0]); + + return { + setShader: setShader, + setPostProcess: setPostProcess + }; +} + +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports = __webpack_require__.p + "index.html"; + +/***/ }), +/* 8 */ +/***/ (function(module, exports) { + +// stats.js - http://github.com/mrdoob/stats.js +var Stats=function(){var l=Date.now(),m=l,g=0,n=Infinity,o=0,h=0,p=Infinity,q=0,r=0,s=0,f=document.createElement("div");f.id="stats";f.addEventListener("mousedown",function(b){b.preventDefault();t(++s%2)},!1);f.style.cssText="width:80px;opacity:0.9;cursor:pointer";var a=document.createElement("div");a.id="fps";a.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#002";f.appendChild(a);var i=document.createElement("div");i.id="fpsText";i.style.cssText="color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px"; +i.innerHTML="FPS";a.appendChild(i);var c=document.createElement("div");c.id="fpsGraph";c.style.cssText="position:relative;width:74px;height:30px;background-color:#0ff";for(a.appendChild(c);74>c.children.length;){var j=document.createElement("span");j.style.cssText="width:1px;height:30px;float:left;background-color:#113";c.appendChild(j)}var d=document.createElement("div");d.id="ms";d.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#020;display:none";f.appendChild(d);var k=document.createElement("div"); +k.id="msText";k.style.cssText="color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";k.innerHTML="MS";d.appendChild(k);var e=document.createElement("div");e.id="msGraph";e.style.cssText="position:relative;width:74px;height:30px;background-color:#0f0";for(d.appendChild(e);74>e.children.length;)j=document.createElement("span"),j.style.cssText="width:1px;height:30px;float:left;background-color:#131",e.appendChild(j);var t=function(b){s=b;switch(s){case 0:a.style.display= +"block";d.style.display="none";break;case 1:a.style.display="none",d.style.display="block"}};return{REVISION:12,domElement:f,setMode:t,begin:function(){l=Date.now()},end:function(){var b=Date.now();g=b-l;n=Math.min(n,g);o=Math.max(o,g);k.textContent=g+" MS ("+n+"-"+o+")";var a=Math.min(30,30-30*(g/200));e.appendChild(e.firstChild).style.height=a+"px";r++;b>m+1E3&&(h=Math.round(1E3*r/(b-m)),p=Math.min(p,h),q=Math.max(q,h),i.textContent=h+" FPS ("+p+"-"+q+")",a=Math.min(30,30-30*(h/100)),c.appendChild(c.firstChild).style.height= +a+"px",m=b,r=0);return b},update:function(){l=this.end()}}};"object"===typeof module&&(module.exports=Stats); + + +/***/ }), +/* 9 */ +/***/ (function(module, exports) { + +module.exports = function( THREE ) { + /** + * @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 + */ + +// This set of controls performs orbiting, dollying (zooming), and panning. +// Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). +// +// 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 finter swipe + + function OrbitControls( object, domElement ) { + + this.object = object; + + this.domElement = ( domElement !== undefined ) ? domElement : document; + + // Set to false to disable this control + this.enabled = true; + + // "target" sets the location of focus, where the object orbits around + this.target = new THREE.Vector3(); + + // How far you can dolly in and out ( PerspectiveCamera only ) + this.minDistance = 0; + this.maxDistance = Infinity; + + // How far you can zoom in and out ( OrthographicCamera only ) + this.minZoom = 0; + this.maxZoom = Infinity; + + // How far you can orbit vertically, upper and lower limits. + // Range is 0 to Math.PI radians. + this.minPolarAngle = 0; // radians + this.maxPolarAngle = Math.PI; // radians + + // How far you can orbit horizontally, upper and lower limits. + // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ]. + this.minAzimuthAngle = - Infinity; // radians + this.maxAzimuthAngle = Infinity; // radians + + // Set to true to enable damping (inertia) + // If damping is enabled, you must call controls.update() in your animation loop + this.enableDamping = false; + this.dampingFactor = 0.25; + + // This option actually enables dollying in and out; left as "zoom" for backwards compatibility. + // Set to false to disable zooming + this.enableZoom = true; + this.zoomSpeed = 1.0; + + // Set to false to disable rotating + this.enableRotate = true; + this.rotateSpeed = 1.0; + + // Set to false to disable panning + this.enablePan = true; + this.keyPanSpeed = 7.0; // pixels moved per arrow key push + + // Set to true to automatically rotate around the target + // If auto-rotate is enabled, you must call controls.update() in your animation loop + this.autoRotate = false; + this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 + + // Set to false to disable use of the keys + this.enableKeys = true; + + // The four arrow keys + this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; + + // Mouse buttons + this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT }; + + // for reset + this.target0 = this.target.clone(); + this.position0 = this.object.position.clone(); + this.zoom0 = this.object.zoom; + + // + // public methods + // + + this.getPolarAngle = function () { + + return spherical.phi; + + }; + + this.getAzimuthalAngle = function () { + + return spherical.theta; + + }; + + this.reset = function () { + + scope.target.copy( scope.target0 ); + scope.object.position.copy( scope.position0 ); + scope.object.zoom = scope.zoom0; + + scope.object.updateProjectionMatrix(); + scope.dispatchEvent( changeEvent ); + + scope.update(); + + state = STATE.NONE; + + }; + + // this method is exposed, but perhaps it would be better if we can make it private... + this.update = function() { + + var offset = new THREE.Vector3(); + + // so camera.up is the orbit axis + var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) ); + var quatInverse = quat.clone().inverse(); + + var lastPosition = new THREE.Vector3(); + var lastQuaternion = new THREE.Quaternion(); + + return function update () { + + var position = scope.object.position; + + offset.copy( position ).sub( scope.target ); + + // rotate offset to "y-axis-is-up" space + offset.applyQuaternion( quat ); + + // angle from z-axis around y-axis + spherical.setFromVector3( offset ); + + if ( scope.autoRotate && state === STATE.NONE ) { + + rotateLeft( getAutoRotationAngle() ); + + } + + spherical.theta += sphericalDelta.theta; + spherical.phi += sphericalDelta.phi; + + // restrict theta to be between desired limits + spherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) ); + + // restrict phi to be between desired limits + spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) ); + + spherical.makeSafe(); + + + spherical.radius *= scale; + + // restrict radius to be between desired limits + spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) ); + + // move target to panned location + scope.target.add( panOffset ); + + offset.setFromSpherical( spherical ); + + // rotate offset back to "camera-up-vector-is-up" space + offset.applyQuaternion( quatInverse ); + + position.copy( scope.target ).add( offset ); + + scope.object.lookAt( scope.target ); + + if ( scope.enableDamping === true ) { + + sphericalDelta.theta *= ( 1 - scope.dampingFactor ); + sphericalDelta.phi *= ( 1 - scope.dampingFactor ); + + } else { + + sphericalDelta.set( 0, 0, 0 ); + + } + + scale = 1; + panOffset.set( 0, 0, 0 ); + + // update condition is: + // min(camera displacement, camera rotation in radians)^2 > EPS + // using small-angle approximation cos(x/2) = 1 - x^2 / 8 + + if ( zoomChanged || + lastPosition.distanceToSquared( scope.object.position ) > EPS || + 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) { + + scope.dispatchEvent( changeEvent ); + + lastPosition.copy( scope.object.position ); + lastQuaternion.copy( scope.object.quaternion ); + zoomChanged = false; + + return true; + + } + + return false; + + }; + + }(); + + this.dispose = function() { + + scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false ); + scope.domElement.removeEventListener( 'mousedown', onMouseDown, false ); + scope.domElement.removeEventListener( 'wheel', onMouseWheel, false ); + + scope.domElement.removeEventListener( 'touchstart', onTouchStart, false ); + scope.domElement.removeEventListener( 'touchend', onTouchEnd, false ); + scope.domElement.removeEventListener( 'touchmove', onTouchMove, false ); + + document.removeEventListener( 'mousemove', onMouseMove, false ); + document.removeEventListener( 'mouseup', onMouseUp, false ); + + window.removeEventListener( 'keydown', onKeyDown, false ); + + //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here? + + }; + + // + // internals + // + + var scope = this; + + var changeEvent = { type: 'change' }; + var startEvent = { type: 'start' }; + var endEvent = { type: 'end' }; + + var STATE = { NONE : - 1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 }; + + var state = STATE.NONE; + + var EPS = 0.000001; + + // current position in spherical coordinates + var spherical = new THREE.Spherical(); + var sphericalDelta = new THREE.Spherical(); + + var scale = 1; + var panOffset = new THREE.Vector3(); + var zoomChanged = false; + + var rotateStart = new THREE.Vector2(); + var rotateEnd = new THREE.Vector2(); + var rotateDelta = new THREE.Vector2(); + + var panStart = new THREE.Vector2(); + var panEnd = new THREE.Vector2(); + var panDelta = new THREE.Vector2(); + + var dollyStart = new THREE.Vector2(); + var dollyEnd = new THREE.Vector2(); + var dollyDelta = new THREE.Vector2(); + + function getAutoRotationAngle() { + + return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; + + } + + function getZoomScale() { + + return Math.pow( 0.95, scope.zoomSpeed ); + + } + + function rotateLeft( angle ) { + + sphericalDelta.theta -= angle; + + } + + function rotateUp( angle ) { + + sphericalDelta.phi -= angle; + + } + + var panLeft = function() { + + var v = new THREE.Vector3(); + + return function panLeft( distance, objectMatrix ) { + + v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix + v.multiplyScalar( - distance ); + + panOffset.add( v ); + + }; + + }(); + + var panUp = function() { + + var v = new THREE.Vector3(); + + return function panUp( distance, objectMatrix ) { + + v.setFromMatrixColumn( objectMatrix, 1 ); // get Y column of objectMatrix + v.multiplyScalar( distance ); + + panOffset.add( v ); + + }; + + }(); + + // deltaX and deltaY are in pixels; right and down are positive + var pan = function() { + + var offset = new THREE.Vector3(); + + return function pan ( deltaX, deltaY ) { + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + if ( scope.object instanceof THREE.PerspectiveCamera ) { + + // perspective + var position = scope.object.position; + offset.copy( position ).sub( scope.target ); + var targetDistance = offset.length(); + + // half of the fov is center to top of screen + targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 ); + + // we actually don't use screenWidth, since perspective camera is fixed to screen height + panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix ); + panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix ); + + } else if ( scope.object instanceof THREE.OrthographicCamera ) { + + // orthographic + panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix ); + panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix ); + + } else { + + // camera neither orthographic nor perspective + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); + scope.enablePan = false; + + } + + }; + + }(); + + function dollyIn( dollyScale ) { + + if ( scope.object instanceof THREE.PerspectiveCamera ) { + + scale /= dollyScale; + + } else if ( scope.object instanceof THREE.OrthographicCamera ) { + + scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + } else { + + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); + scope.enableZoom = false; + + } + + } + + function dollyOut( dollyScale ) { + + if ( scope.object instanceof THREE.PerspectiveCamera ) { + + scale *= dollyScale; + + } else if ( scope.object instanceof THREE.OrthographicCamera ) { + + scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + } else { + + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); + scope.enableZoom = false; + + } + + } + + // + // event callbacks - update the object state + // + + function handleMouseDownRotate( event ) { + + //console.log( 'handleMouseDownRotate' ); + + rotateStart.set( event.clientX, event.clientY ); + + } + + function handleMouseDownDolly( event ) { + + //console.log( 'handleMouseDownDolly' ); + + dollyStart.set( event.clientX, event.clientY ); + + } + + function handleMouseDownPan( event ) { + + //console.log( 'handleMouseDownPan' ); + + panStart.set( event.clientX, event.clientY ); + + } + + function handleMouseMoveRotate( event ) { + + //console.log( 'handleMouseMoveRotate' ); + + rotateEnd.set( event.clientX, event.clientY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + // rotating across whole screen goes 360 degrees around + rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); + + // rotating up and down along whole screen attempts to go 360, but limited to 180 + rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); + + rotateStart.copy( rotateEnd ); + + scope.update(); + + } + + function handleMouseMoveDolly( event ) { + + //console.log( 'handleMouseMoveDolly' ); + + dollyEnd.set( event.clientX, event.clientY ); + + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + dollyIn( getZoomScale() ); + + } else if ( dollyDelta.y < 0 ) { + + dollyOut( getZoomScale() ); + + } + + dollyStart.copy( dollyEnd ); + + scope.update(); + + } + + function handleMouseMovePan( event ) { + + //console.log( 'handleMouseMovePan' ); + + panEnd.set( event.clientX, event.clientY ); + + panDelta.subVectors( panEnd, panStart ); + + pan( panDelta.x, panDelta.y ); + + panStart.copy( panEnd ); + + scope.update(); + + } + + function handleMouseUp( event ) { + + //console.log( 'handleMouseUp' ); + + } + + function handleMouseWheel( event ) { + + //console.log( 'handleMouseWheel' ); + + if ( event.deltaY < 0 ) { + + dollyOut( getZoomScale() ); + + } else if ( event.deltaY > 0 ) { + + dollyIn( getZoomScale() ); + + } + + scope.update(); + + } + + function handleKeyDown( event ) { + + //console.log( 'handleKeyDown' ); + + switch ( event.keyCode ) { + + case scope.keys.UP: + pan( 0, scope.keyPanSpeed ); + scope.update(); + break; + + case scope.keys.BOTTOM: + pan( 0, - scope.keyPanSpeed ); + scope.update(); + break; + + case scope.keys.LEFT: + pan( scope.keyPanSpeed, 0 ); + scope.update(); + break; + + case scope.keys.RIGHT: + pan( - scope.keyPanSpeed, 0 ); + scope.update(); + break; + + } + + } + + function handleTouchStartRotate( event ) { + + //console.log( 'handleTouchStartRotate' ); + + rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + + } + + function handleTouchStartDolly( event ) { + + //console.log( 'handleTouchStartDolly' ); + + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + + var distance = Math.sqrt( dx * dx + dy * dy ); + + dollyStart.set( 0, distance ); + + } + + function handleTouchStartPan( event ) { + + //console.log( 'handleTouchStartPan' ); + + panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + + } + + function handleTouchMoveRotate( event ) { + + //console.log( 'handleTouchMoveRotate' ); + + rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + // rotating across whole screen goes 360 degrees around + rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); + + // rotating up and down along whole screen attempts to go 360, but limited to 180 + rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); + + rotateStart.copy( rotateEnd ); + + scope.update(); + + } + + function handleTouchMoveDolly( event ) { + + //console.log( 'handleTouchMoveDolly' ); + + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + + var distance = Math.sqrt( dx * dx + dy * dy ); + + dollyEnd.set( 0, distance ); + + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + dollyOut( getZoomScale() ); + + } else if ( dollyDelta.y < 0 ) { + + dollyIn( getZoomScale() ); + + } + + dollyStart.copy( dollyEnd ); + + scope.update(); + + } + + function handleTouchMovePan( event ) { + + //console.log( 'handleTouchMovePan' ); + + panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + + panDelta.subVectors( panEnd, panStart ); + + pan( panDelta.x, panDelta.y ); + + panStart.copy( panEnd ); + + scope.update(); + + } + + function handleTouchEnd( event ) { + + //console.log( 'handleTouchEnd' ); + + } + + // + // event handlers - FSM: listen for events and reset state + // + + function onMouseDown( event ) { + + if ( scope.enabled === false ) return; + + event.preventDefault(); + + if ( event.button === scope.mouseButtons.ORBIT ) { + + if ( scope.enableRotate === false ) return; + + handleMouseDownRotate( event ); + + state = STATE.ROTATE; + + } else if ( event.button === scope.mouseButtons.ZOOM ) { + + if ( scope.enableZoom === false ) return; + + handleMouseDownDolly( event ); + + state = STATE.DOLLY; + + } else if ( event.button === scope.mouseButtons.PAN ) { + + if ( scope.enablePan === false ) return; + + handleMouseDownPan( event ); + + state = STATE.PAN; + + } + + if ( state !== STATE.NONE ) { + + document.addEventListener( 'mousemove', onMouseMove, false ); + document.addEventListener( 'mouseup', onMouseUp, false ); + + scope.dispatchEvent( startEvent ); + + } + + } + + function onMouseMove( event ) { + + if ( scope.enabled === false ) return; + + event.preventDefault(); + + if ( state === STATE.ROTATE ) { + + if ( scope.enableRotate === false ) return; + + handleMouseMoveRotate( event ); + + } else if ( state === STATE.DOLLY ) { + + if ( scope.enableZoom === false ) return; + + handleMouseMoveDolly( event ); + + } else if ( state === STATE.PAN ) { + + if ( scope.enablePan === false ) return; + + handleMouseMovePan( event ); + + } + + } + + function onMouseUp( event ) { + + if ( scope.enabled === false ) return; + + handleMouseUp( event ); + + document.removeEventListener( 'mousemove', onMouseMove, false ); + document.removeEventListener( 'mouseup', onMouseUp, false ); + + scope.dispatchEvent( endEvent ); + + state = STATE.NONE; + + } + + function onMouseWheel( event ) { + + if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return; + + event.preventDefault(); + event.stopPropagation(); + + handleMouseWheel( event ); + + scope.dispatchEvent( startEvent ); // not sure why these are here... + scope.dispatchEvent( endEvent ); + + } + + function onKeyDown( event ) { + + if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return; + + handleKeyDown( event ); + + } + + function onTouchStart( event ) { + + if ( scope.enabled === false ) return; + + switch ( event.touches.length ) { + + case 1: // one-fingered touch: rotate + + if ( scope.enableRotate === false ) return; + + handleTouchStartRotate( event ); + + state = STATE.TOUCH_ROTATE; + + break; + + case 2: // two-fingered touch: dolly + + if ( scope.enableZoom === false ) return; + + handleTouchStartDolly( event ); + + state = STATE.TOUCH_DOLLY; + + break; + + case 3: // three-fingered touch: pan + + if ( scope.enablePan === false ) return; + + handleTouchStartPan( event ); + + state = STATE.TOUCH_PAN; + + break; + + default: + + state = STATE.NONE; + + } + + if ( state !== STATE.NONE ) { + + scope.dispatchEvent( startEvent ); + + } + + } + + function onTouchMove( event ) { + + if ( scope.enabled === false ) return; + + event.preventDefault(); + event.stopPropagation(); + + switch ( event.touches.length ) { + + case 1: // one-fingered touch: rotate + + if ( scope.enableRotate === false ) return; + if ( state !== STATE.TOUCH_ROTATE ) return; // is this needed?... + + handleTouchMoveRotate( event ); + + break; + + case 2: // two-fingered touch: dolly + + if ( scope.enableZoom === false ) return; + if ( state !== STATE.TOUCH_DOLLY ) return; // is this needed?... + + handleTouchMoveDolly( event ); + + break; + + case 3: // three-fingered touch: pan + + if ( scope.enablePan === false ) return; + if ( state !== STATE.TOUCH_PAN ) return; // is this needed?... + + handleTouchMovePan( event ); + + break; + + default: + + state = STATE.NONE; + + } + + } + + function onTouchEnd( event ) { + + if ( scope.enabled === false ) return; + + handleTouchEnd( event ); + + scope.dispatchEvent( endEvent ); + + state = STATE.NONE; + + } + + function onContextMenu( event ) { + + event.preventDefault(); + + } + + // + + scope.domElement.addEventListener( 'contextmenu', onContextMenu, false ); + + scope.domElement.addEventListener( 'mousedown', onMouseDown, false ); + scope.domElement.addEventListener( 'wheel', onMouseWheel, false ); + + scope.domElement.addEventListener( 'touchstart', onTouchStart, false ); + scope.domElement.addEventListener( 'touchend', onTouchEnd, false ); + scope.domElement.addEventListener( 'touchmove', onTouchMove, false ); + + window.addEventListener( 'keydown', onKeyDown, false ); + + // force an update at start + + this.update(); + + }; + + OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); + OrbitControls.prototype.constructor = OrbitControls; + + Object.defineProperties( OrbitControls.prototype, { + + center: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .center has been renamed to .target' ); + return this.target; + + } + + }, + + // backward compatibility + + noZoom: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); + return ! this.enableZoom; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); + this.enableZoom = ! value; + + } + + }, + + noRotate: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); + return ! this.enableRotate; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); + this.enableRotate = ! value; + + } + + }, + + noPan: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); + return ! this.enablePan; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); + this.enablePan = ! value; + + } + + }, + + noKeys: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); + return ! this.enableKeys; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); + this.enableKeys = ! value; + + } + + }, + + staticMoving : { + + get: function () { + + console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); + return ! this.enableDamping; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); + this.enableDamping = ! value; + + } + + }, + + dynamicDampingFactor : { + + get: function () { + + console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); + return this.dampingFactor; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); + this.dampingFactor = value; + + } + + } + + } ); + + return OrbitControls; +}; + + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +// this file is just for convenience. it sets up loading the mario obj and texture + +var THREE = __webpack_require__(0); +__webpack_require__(5)(THREE); + +var textureLoaded = exports.textureLoaded = new Promise(function (resolve, reject) { + new THREE.TextureLoader().load(__webpack_require__(25), function (texture) { + resolve(texture); + }); +}); + +var objLoaded = exports.objLoaded = new Promise(function (resolve, reject) { + new THREE.OBJLoader().load(__webpack_require__(4), function (obj) { + var geo = obj.children[0].geometry; + geo.computeBoundingSphere(); + resolve(geo); + }); +}); + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = Gaussian; +var THREE = __webpack_require__(0); +var EffectComposer = __webpack_require__(1)(THREE); + +var options = { + amount: 1 +}; +var GaussianShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_amount: { + type: 'f', + value: options.amount + }, + sHeight: { + type: 'f', + value: screen.height + }, + sWidth: { + type: 'f', + value: screen.width + } + }, + vertexShader: __webpack_require__(2), + fragmentShader: __webpack_require__(32) +}); + +function Gaussian(renderer, scene, camera) { + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + + // first render the scene normally and add that as the first pass + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + + // then take the rendered result and apply the GaussianShader + composer.addPass(GaussianShader); + + // set this to true on the shader for your last pass to write to the screen + GaussianShader.renderToScreen = true; + + return { + initGUI: function initGUI(gui) { + gui.add(options, 'amount', 0, 1).onChange(function (val) { + GaussianShader.material.uniforms.u_amount.value = val; + }); + }, + + render: function render() { + ; + composer.render(); + } + }; +} + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = Grayscale; +var THREE = __webpack_require__(0); +var EffectComposer = __webpack_require__(1)(THREE); + +var options = { + amount: 1 +}; + +var GrayscaleShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_amount: { + type: 'f', + value: options.amount + } + }, + vertexShader: __webpack_require__(2), + fragmentShader: __webpack_require__(33) +}); + +function Grayscale(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + + // first render the scene normally and add that as the first pass + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + + // then take the rendered result and apply the GrayscaleShader + composer.addPass(GrayscaleShader); + + // set this to true on the shader for your last pass to write to the screen + GrayscaleShader.renderToScreen = true; + + return { + initGUI: function initGUI(gui) { + gui.add(options, 'amount', 0, 1).onChange(function (val) { + GrayscaleShader.material.uniforms.u_amount.value = val; + }); + }, + + render: function render() { + ; + composer.render(); + } + }; +} + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.None = None; + +var _grayscale = __webpack_require__(12); + +Object.defineProperty(exports, 'Grayscale', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_grayscale).default; + } +}); + +var _invert = __webpack_require__(14); + +Object.defineProperty(exports, 'Invert', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_invert).default; + } +}); + +var _sobel = __webpack_require__(16); + +Object.defineProperty(exports, 'Sobel', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_sobel).default; + } +}); + +var _vignette = __webpack_require__(17); + +Object.defineProperty(exports, 'Vignette', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_vignette).default; + } +}); + +var _gaussian = __webpack_require__(11); + +Object.defineProperty(exports, 'Gaussian', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_gaussian).default; + } +}); + +var _pointilism = __webpack_require__(15); + +Object.defineProperty(exports, 'Pointilism', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_pointilism).default; + } +}); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +// This file exports available shaders to the GUI. + +// don't worry about this one. This is just to apply no filter +function None(renderer, scene, camera) { + return { + initGUI: function initGUI(gui) {}, + + render: function render() { + renderer.render(scene, camera); + } + }; +} + +// follow this syntax to make your shaders available to the GUI + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = invert; +var THREE = __webpack_require__(0); +var EffectComposer = __webpack_require__(1)(THREE); + +var options = { + amount: 1 +}; +var t = new Date(); +var invertShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_amount: { + type: 'f', + value: options.amount + }, + time: { + type: 'f', + value: t.getTime() + } + }, + vertexShader: __webpack_require__(2), + fragmentShader: __webpack_require__(34) +}); + +function invert(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + + // first render the scene normally and add that as the first pass + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + + // then take the rendered result and apply the GrayscaleShader + composer.addPass(invertShader); + + // set this to true on the shader for your last pass to write to the screen + invertShader.renderToScreen = true; + + return { + initGUI: function initGUI(gui) { + gui.add(options, 'amount', 0, 1).onChange(function (val) { + invertShader.material.uniforms.u_amount.value = val; + }); + }, + + render: function render() { + ; + composer.render(); + } + }; +} + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = Pointilism; +var THREE = __webpack_require__(0); +var EffectComposer = __webpack_require__(1)(THREE); + +var options = { + amount: 1 +}; +var PointilismShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_amount: { + type: 'f', + value: options.amount + }, + sHeight: { + type: 'f', + value: screen.height + }, + sWidth: { + type: 'f', + value: screen.width + } + }, + vertexShader: __webpack_require__(2), + fragmentShader: __webpack_require__(39) +}); + +function Pointilism(renderer, scene, camera) { + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + + // first render the scene normally and add that as the first pass + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + + // then take the rendered result and apply the PointilismShader + composer.addPass(PointilismShader); + + // set this to true on the shader for your last pass to write to the screen + PointilismShader.renderToScreen = true; + + return { + initGUI: function initGUI(gui) { + gui.add(options, 'amount', 0, 1).onChange(function (val) { + PointilismShader.material.uniforms.u_amount.value = val; + }); + }, + + render: function render() { + ; + composer.render(); + } + }; +} + +/***/ }), +/* 16 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = Grayscale; +var THREE = __webpack_require__(0); +var EffectComposer = __webpack_require__(1)(THREE); + +var options = { + amount: 1 +}; +var SobelShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_amount: { + type: 'f', + value: options.amount + }, + sHeight: { + type: 'f', + value: screen.height + }, + sWidth: { + type: 'f', + value: screen.width + } + }, + vertexShader: __webpack_require__(2), + fragmentShader: __webpack_require__(40) +}); + +function Grayscale(renderer, scene, camera) { + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + + // first render the scene normally and add that as the first pass + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + + // then take the rendered result and apply the SobelShader + composer.addPass(SobelShader); + + // set this to true on the shader for your last pass to write to the screen + SobelShader.renderToScreen = true; + + return { + initGUI: function initGUI(gui) { + gui.add(options, 'amount', 0, 1).onChange(function (val) { + SobelShader.material.uniforms.u_amount.value = val; + }); + }, + + render: function render() { + ; + composer.render(); + } + }; +} + +/***/ }), +/* 17 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = Vignette; +var THREE = __webpack_require__(0); +var EffectComposer = __webpack_require__(1)(THREE); + +var options = { + amount: 1, + color: '#ffffff' +}; + +var VignetteShaders = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_amount: { + type: 'f', + value: options.amount + }, + u_color: { + type: 'v3', + value: new THREE.Color(options.lightColor) + } + }, + vertexShader: __webpack_require__(2), + fragmentShader: __webpack_require__(43) +}); + +function Vignette(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + + // first render the scene normally and add that as the first pass + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + + // then take the rendered result and apply the VignetteShaders + composer.addPass(VignetteShaders); + + // set this to true on the shader for your last pass to write to the screen + VignetteShaders.renderToScreen = true; + + return { + initGUI: function initGUI(gui) { + gui.add(options, 'amount', 0, 1).onChange(function (val) { + VignetteShaders.material.uniforms.u_amount.value = val; + }); + gui.addColor(options, 'color').onChange(function (val) { + VignetteShaders.material.uniforms.u_color.value = new THREE.Color(val); + }); + }, + + render: function render() { + ; + composer.render(); + } + }; +} + +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _lambert = __webpack_require__(20); + +Object.defineProperty(exports, 'Lambert', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_lambert).default; + } +}); + +var _toon = __webpack_require__(21); + +Object.defineProperty(exports, 'Toon', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_toon).default; + } +}); + +var _iridescent = __webpack_require__(19); + +Object.defineProperty(exports, 'Iridescent', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_iridescent).default; + } +}); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +exports.default = function (renderer, scene, camera) { + var Shader = { + initGUI: function initGUI(gui) { + gui.addColor(options, 'lightColor').onChange(function (val) { + Shader.material.uniforms.u_lightCol.value = new THREE.Color(val); + }); + gui.add(options, 'lightIntensity').onChange(function (val) { + Shader.material.uniforms.u_lightIntensity.value = val; + }); + gui.addColor(options, 'albedo').onChange(function (val) { + Shader.material.uniforms.u_albedo.value = new THREE.Color(val); + }); + gui.addColor(options, 'ambient').onChange(function (val) { + Shader.material.uniforms.u_ambient.value = new THREE.Color(val); + }); + gui.add(options, 'useTexture').onChange(function (val) { + Shader.material.uniforms.u_useTexture.value = val; + }); + }, + + material: new THREE.ShaderMaterial({ + uniforms: { + texture: { + type: "t", + value: null + }, + u_useTexture: { + type: 'i', + value: options.useTexture + }, + u_albedo: { + type: 'v3', + value: new THREE.Color(options.albedo) + }, + u_ambient: { + type: 'v3', + value: new THREE.Color(options.ambient) + }, + u_lightPos: { + type: 'v3', + value: new THREE.Vector3(30, 50, 40) + }, + u_lightCol: { + type: 'v3', + value: new THREE.Color(options.lightColor) + }, + u_lightIntensity: { + type: 'f', + value: options.lightIntensity + }, + u_camPos: { + type: 'v3', + value: camera.position + } + }, + vertexShader: __webpack_require__(36), + fragmentShader: __webpack_require__(35) + }) + }; + + // once the Mario texture loads, bind it to the material + _iridescentmario.textureLoaded.then(function (texture) { + Shader.material.uniforms.texture.value = texture; + }); + + return Shader; +}; + +var _iridescentmario = __webpack_require__(10); + +var THREE = __webpack_require__(0); + + +// options for lambert shader +var options = { + lightColor: '#ffffff', + lightIntensity: 2, + albedo: '#dddddd', + ambient: '#111111', + useTexture: true +}; + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +exports.default = function (renderer, scene, camera) { + + var Shader = { + initGUI: function initGUI(gui) { + gui.addColor(options, 'lightColor').onChange(function (val) { + Shader.material.uniforms.u_lightCol.value = new THREE.Color(val); + }); + gui.add(options, 'lightIntensity').onChange(function (val) { + Shader.material.uniforms.u_lightIntensity.value = val; + }); + gui.addColor(options, 'albedo').onChange(function (val) { + Shader.material.uniforms.u_albedo.value = new THREE.Color(val); + }); + gui.addColor(options, 'ambient').onChange(function (val) { + Shader.material.uniforms.u_ambient.value = new THREE.Color(val); + }); + gui.add(options, 'useTexture').onChange(function (val) { + Shader.material.uniforms.u_useTexture.value = val; + }); + }, + + material: new THREE.ShaderMaterial({ + uniforms: { + texture: { + type: "t", + value: null + }, + u_useTexture: { + type: 'i', + value: options.useTexture + }, + u_albedo: { + type: 'v3', + value: new THREE.Color(options.albedo) + }, + u_ambient: { + type: 'v3', + value: new THREE.Color(options.ambient) + }, + u_lightPos: { + type: 'v3', + value: new THREE.Vector3(30, 50, 40) + }, + u_lightCol: { + type: 'v3', + value: new THREE.Color(options.lightColor) + }, + u_lightIntensity: { + type: 'f', + value: options.lightIntensity + } + }, + vertexShader: __webpack_require__(38), + fragmentShader: __webpack_require__(37) + }) + }; + + // once the Mario texture loads, bind it to the material + _mario.textureLoaded.then(function (texture) { + Shader.material.uniforms.texture.value = texture; + }); + + return Shader; +}; + +var _mario = __webpack_require__(3); + +var THREE = __webpack_require__(0); + + +// options for lambert shader +var options = { + lightColor: '#ffffff', + lightIntensity: 2, + albedo: '#dddddd', + ambient: '#111111', + useTexture: true +}; + +/***/ }), +/* 21 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +exports.default = function (renderer, scene, camera) { + var pLocal = new THREE.Vector3(0, 0, -1); + var pWorld = pLocal.applyMatrix4(camera.matrixWorld); + var dir = pWorld.sub(camera.position).normalize(); + var Shader = { + initGUI: function initGUI(gui) { + gui.addColor(options, 'lightColor').onChange(function (val) { + Shader.material.uniforms.u_lightCol.value = new THREE.Color(val); + }); + gui.add(options, 'lightIntensity').onChange(function (val) { + Shader.material.uniforms.u_lightIntensity.value = val; + }); + gui.addColor(options, 'albedo').onChange(function (val) { + Shader.material.uniforms.u_albedo.value = new THREE.Color(val); + }); + gui.addColor(options, 'ambient').onChange(function (val) { + Shader.material.uniforms.u_ambient.value = new THREE.Color(val); + }); + gui.add(options, 'useTexture').onChange(function (val) { + Shader.material.uniforms.u_useTexture.value = val; + }); + }, + + material: new THREE.ShaderMaterial({ + uniforms: { + texture: { + type: "t", + value: null + }, + u_useTexture: { + type: 'i', + value: options.useTexture + }, + u_albedo: { + type: 'v3', + value: new THREE.Color(options.albedo) + }, + u_ambient: { + type: 'v3', + value: new THREE.Color(options.ambient) + }, + u_lightPos: { + type: 'v3', + value: new THREE.Vector3(30, 50, 40) + }, + u_lightCol: { + type: 'v3', + value: new THREE.Color(options.lightColor) + }, + u_lightIntensity: { + type: 'f', + value: options.lightIntensity + }, + u_camPos: { + type: 'v3', + value: camera.position + }, + u_camDir: { + type: 'v3', + value: dir + } + }, + vertexShader: __webpack_require__(42), + fragmentShader: __webpack_require__(41) + }) + }; + + // once the Mario texture loads, bind it to the material + _mario.textureLoaded.then(function (texture) { + Shader.material.uniforms.texture.value = texture; + }); + + return Shader; +}; + +var _mario = __webpack_require__(3); + +var THREE = __webpack_require__(0); + + +// options for lambert shader +var options = { + lightColor: '#ffffff', + lightIntensity: 2, + albedo: '#dddddd', + ambient: '#111111', + useTexture: true +}; + +/***/ }), +/* 22 */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports = __webpack_require__(24) +module.exports.color = __webpack_require__(23) + +/***/ }), +/* 23 */ +/***/ (function(module, exports) { + +/** + * dat-gui JavaScript Controller Library + * http://code.google.com/p/dat-gui + * + * Copyright 2011 Data Arts Team, Google Creative Lab + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + +/** @namespace */ +var dat = module.exports = dat || {}; + +/** @namespace */ +dat.color = dat.color || {}; + +/** @namespace */ +dat.utils = dat.utils || {}; + +dat.utils.common = (function () { + + var ARR_EACH = Array.prototype.forEach; + var ARR_SLICE = Array.prototype.slice; + + /** + * Band-aid methods for things that should be a lot easier in JavaScript. + * Implementation and structure inspired by underscore.js + * http://documentcloud.github.com/underscore/ + */ + + return { + + BREAK: {}, + + extend: function(target) { + + this.each(ARR_SLICE.call(arguments, 1), function(obj) { + + for (var key in obj) + if (!this.isUndefined(obj[key])) + target[key] = obj[key]; + + }, this); + + return target; + + }, + + defaults: function(target) { + + this.each(ARR_SLICE.call(arguments, 1), function(obj) { + + for (var key in obj) + if (this.isUndefined(target[key])) + target[key] = obj[key]; + + }, this); + + return target; + + }, + + compose: function() { + var toCall = ARR_SLICE.call(arguments); + return function() { + var args = ARR_SLICE.call(arguments); + for (var i = toCall.length -1; i >= 0; i--) { + args = [toCall[i].apply(this, args)]; + } + return args[0]; + } + }, + + each: function(obj, itr, scope) { + + + if (ARR_EACH && obj.forEach === ARR_EACH) { + + obj.forEach(itr, scope); + + } else if (obj.length === obj.length + 0) { // Is number but not NaN + + for (var key = 0, l = obj.length; key < l; key++) + if (key in obj && itr.call(scope, obj[key], key) === this.BREAK) + return; + + } else { + + for (var key in obj) + if (itr.call(scope, obj[key], key) === this.BREAK) + return; + + } + + }, + + defer: function(fnc) { + setTimeout(fnc, 0); + }, + + toArray: function(obj) { + if (obj.toArray) return obj.toArray(); + return ARR_SLICE.call(obj); + }, + + isUndefined: function(obj) { + return obj === undefined; + }, + + isNull: function(obj) { + return obj === null; + }, + + isNaN: function(obj) { + return obj !== obj; + }, + + isArray: Array.isArray || function(obj) { + return obj.constructor === Array; + }, + + isObject: function(obj) { + return obj === Object(obj); + }, + + isNumber: function(obj) { + return obj === obj+0; + }, + + isString: function(obj) { + return obj === obj+''; + }, + + isBoolean: function(obj) { + return obj === false || obj === true; + }, + + isFunction: function(obj) { + return Object.prototype.toString.call(obj) === '[object Function]'; + } + + }; + +})(); + + +dat.color.toString = (function (common) { + + return function(color) { + + if (color.a == 1 || common.isUndefined(color.a)) { + + var s = color.hex.toString(16); + while (s.length < 6) { + s = '0' + s; + } + + return '#' + s; + + } else { + + return 'rgba(' + Math.round(color.r) + ',' + Math.round(color.g) + ',' + Math.round(color.b) + ',' + color.a + ')'; + + } + + } + +})(dat.utils.common); + + +dat.Color = dat.color.Color = (function (interpret, math, toString, common) { + + var Color = function() { + + this.__state = interpret.apply(this, arguments); + + if (this.__state === false) { + throw 'Failed to interpret color arguments'; + } + + this.__state.a = this.__state.a || 1; + + + }; + + Color.COMPONENTS = ['r','g','b','h','s','v','hex','a']; + + common.extend(Color.prototype, { + + toString: function() { + return toString(this); + }, + + toOriginal: function() { + return this.__state.conversion.write(this); + } + + }); + + defineRGBComponent(Color.prototype, 'r', 2); + defineRGBComponent(Color.prototype, 'g', 1); + defineRGBComponent(Color.prototype, 'b', 0); + + defineHSVComponent(Color.prototype, 'h'); + defineHSVComponent(Color.prototype, 's'); + defineHSVComponent(Color.prototype, 'v'); + + Object.defineProperty(Color.prototype, 'a', { + + get: function() { + return this.__state.a; + }, + + set: function(v) { + this.__state.a = v; + } + + }); + + Object.defineProperty(Color.prototype, 'hex', { + + get: function() { + + if (!this.__state.space !== 'HEX') { + this.__state.hex = math.rgb_to_hex(this.r, this.g, this.b); + } + + return this.__state.hex; + + }, + + set: function(v) { + + this.__state.space = 'HEX'; + this.__state.hex = v; + + } + + }); + + function defineRGBComponent(target, component, componentHexIndex) { + + Object.defineProperty(target, component, { + + get: function() { + + if (this.__state.space === 'RGB') { + return this.__state[component]; + } + + recalculateRGB(this, component, componentHexIndex); + + return this.__state[component]; + + }, + + set: function(v) { + + if (this.__state.space !== 'RGB') { + recalculateRGB(this, component, componentHexIndex); + this.__state.space = 'RGB'; + } + + this.__state[component] = v; + + } + + }); + + } + + function defineHSVComponent(target, component) { + + Object.defineProperty(target, component, { + + get: function() { + + if (this.__state.space === 'HSV') + return this.__state[component]; + + recalculateHSV(this); + + return this.__state[component]; + + }, + + set: function(v) { + + if (this.__state.space !== 'HSV') { + recalculateHSV(this); + this.__state.space = 'HSV'; + } + + this.__state[component] = v; + + } + + }); + + } + + function recalculateRGB(color, component, componentHexIndex) { + + if (color.__state.space === 'HEX') { + + color.__state[component] = math.component_from_hex(color.__state.hex, componentHexIndex); + + } else if (color.__state.space === 'HSV') { + + common.extend(color.__state, math.hsv_to_rgb(color.__state.h, color.__state.s, color.__state.v)); + + } else { + + throw 'Corrupted color state'; + + } + + } + + function recalculateHSV(color) { + + var result = math.rgb_to_hsv(color.r, color.g, color.b); + + common.extend(color.__state, + { + s: result.s, + v: result.v + } + ); + + if (!common.isNaN(result.h)) { + color.__state.h = result.h; + } else if (common.isUndefined(color.__state.h)) { + color.__state.h = 0; + } + + } + + return Color; + +})(dat.color.interpret = (function (toString, common) { + + var result, toReturn; + + var interpret = function() { + + toReturn = false; + + var original = arguments.length > 1 ? common.toArray(arguments) : arguments[0]; + + common.each(INTERPRETATIONS, function(family) { + + if (family.litmus(original)) { + + common.each(family.conversions, function(conversion, conversionName) { + + result = conversion.read(original); + + if (toReturn === false && result !== false) { + toReturn = result; + result.conversionName = conversionName; + result.conversion = conversion; + return common.BREAK; + + } + + }); + + return common.BREAK; + + } + + }); + + return toReturn; + + }; + + var INTERPRETATIONS = [ + + // Strings + { + + litmus: common.isString, + + conversions: { + + THREE_CHAR_HEX: { + + read: function(original) { + + var test = original.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i); + if (test === null) return false; + + return { + space: 'HEX', + hex: parseInt( + '0x' + + test[1].toString() + test[1].toString() + + test[2].toString() + test[2].toString() + + test[3].toString() + test[3].toString()) + }; + + }, + + write: toString + + }, + + SIX_CHAR_HEX: { + + read: function(original) { + + var test = original.match(/^#([A-F0-9]{6})$/i); + if (test === null) return false; + + return { + space: 'HEX', + hex: parseInt('0x' + test[1].toString()) + }; + + }, + + write: toString + + }, + + CSS_RGB: { + + read: function(original) { + + var test = original.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/); + if (test === null) return false; + + return { + space: 'RGB', + r: parseFloat(test[1]), + g: parseFloat(test[2]), + b: parseFloat(test[3]) + }; + + }, + + write: toString + + }, + + CSS_RGBA: { + + read: function(original) { + + var test = original.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\,\s*(.+)\s*\)/); + if (test === null) return false; + + return { + space: 'RGB', + r: parseFloat(test[1]), + g: parseFloat(test[2]), + b: parseFloat(test[3]), + a: parseFloat(test[4]) + }; + + }, + + write: toString + + } + + } + + }, + + // Numbers + { + + litmus: common.isNumber, + + conversions: { + + HEX: { + read: function(original) { + return { + space: 'HEX', + hex: original, + conversionName: 'HEX' + } + }, + + write: function(color) { + return color.hex; + } + } + + } + + }, + + // Arrays + { + + litmus: common.isArray, + + conversions: { + + RGB_ARRAY: { + read: function(original) { + if (original.length != 3) return false; + return { + space: 'RGB', + r: original[0], + g: original[1], + b: original[2] + }; + }, + + write: function(color) { + return [color.r, color.g, color.b]; + } + + }, + + RGBA_ARRAY: { + read: function(original) { + if (original.length != 4) return false; + return { + space: 'RGB', + r: original[0], + g: original[1], + b: original[2], + a: original[3] + }; + }, + + write: function(color) { + return [color.r, color.g, color.b, color.a]; + } + + } + + } + + }, + + // Objects + { + + litmus: common.isObject, + + conversions: { + + RGBA_OBJ: { + read: function(original) { + if (common.isNumber(original.r) && + common.isNumber(original.g) && + common.isNumber(original.b) && + common.isNumber(original.a)) { + return { + space: 'RGB', + r: original.r, + g: original.g, + b: original.b, + a: original.a + } + } + return false; + }, + + write: function(color) { + return { + r: color.r, + g: color.g, + b: color.b, + a: color.a + } + } + }, + + RGB_OBJ: { + read: function(original) { + if (common.isNumber(original.r) && + common.isNumber(original.g) && + common.isNumber(original.b)) { + return { + space: 'RGB', + r: original.r, + g: original.g, + b: original.b + } + } + return false; + }, + + write: function(color) { + return { + r: color.r, + g: color.g, + b: color.b + } + } + }, + + HSVA_OBJ: { + read: function(original) { + if (common.isNumber(original.h) && + common.isNumber(original.s) && + common.isNumber(original.v) && + common.isNumber(original.a)) { + return { + space: 'HSV', + h: original.h, + s: original.s, + v: original.v, + a: original.a + } + } + return false; + }, + + write: function(color) { + return { + h: color.h, + s: color.s, + v: color.v, + a: color.a + } + } + }, + + HSV_OBJ: { + read: function(original) { + if (common.isNumber(original.h) && + common.isNumber(original.s) && + common.isNumber(original.v)) { + return { + space: 'HSV', + h: original.h, + s: original.s, + v: original.v + } + } + return false; + }, + + write: function(color) { + return { + h: color.h, + s: color.s, + v: color.v + } + } + + } + + } + + } + + + ]; + + return interpret; + + +})(dat.color.toString, +dat.utils.common), +dat.color.math = (function () { + + var tmpComponent; + + return { + + hsv_to_rgb: function(h, s, v) { + + var hi = Math.floor(h / 60) % 6; + + var f = h / 60 - Math.floor(h / 60); + var p = v * (1.0 - s); + var q = v * (1.0 - (f * s)); + var t = v * (1.0 - ((1.0 - f) * s)); + var c = [ + [v, t, p], + [q, v, p], + [p, v, t], + [p, q, v], + [t, p, v], + [v, p, q] + ][hi]; + + return { + r: c[0] * 255, + g: c[1] * 255, + b: c[2] * 255 + }; + + }, + + rgb_to_hsv: function(r, g, b) { + + var min = Math.min(r, g, b), + max = Math.max(r, g, b), + delta = max - min, + h, s; + + if (max != 0) { + s = delta / max; + } else { + return { + h: NaN, + s: 0, + v: 0 + }; + } + + if (r == max) { + h = (g - b) / delta; + } else if (g == max) { + h = 2 + (b - r) / delta; + } else { + h = 4 + (r - g) / delta; + } + h /= 6; + if (h < 0) { + h += 1; + } + + return { + h: h * 360, + s: s, + v: max / 255 + }; + }, + + rgb_to_hex: function(r, g, b) { + var hex = this.hex_with_component(0, 2, r); + hex = this.hex_with_component(hex, 1, g); + hex = this.hex_with_component(hex, 0, b); + return hex; + }, + + component_from_hex: function(hex, componentIndex) { + return (hex >> (componentIndex * 8)) & 0xFF; + }, + + hex_with_component: function(hex, componentIndex, value) { + return value << (tmpComponent = componentIndex * 8) | (hex & ~ (0xFF << tmpComponent)); + } + + } + +})(), +dat.color.toString, +dat.utils.common); + +/***/ }), +/* 24 */ +/***/ (function(module, exports) { + +/** + * dat-gui JavaScript Controller Library + * http://code.google.com/p/dat-gui + * + * Copyright 2011 Data Arts Team, Google Creative Lab + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + +/** @namespace */ +var dat = module.exports = dat || {}; + +/** @namespace */ +dat.gui = dat.gui || {}; + +/** @namespace */ +dat.utils = dat.utils || {}; + +/** @namespace */ +dat.controllers = dat.controllers || {}; + +/** @namespace */ +dat.dom = dat.dom || {}; + +/** @namespace */ +dat.color = dat.color || {}; + +dat.utils.css = (function () { + return { + load: function (url, doc) { + doc = doc || document; + var link = doc.createElement('link'); + link.type = 'text/css'; + link.rel = 'stylesheet'; + link.href = url; + doc.getElementsByTagName('head')[0].appendChild(link); + }, + inject: function(css, doc) { + doc = doc || document; + var injected = document.createElement('style'); + injected.type = 'text/css'; + injected.innerHTML = css; + doc.getElementsByTagName('head')[0].appendChild(injected); + } + } +})(); + + +dat.utils.common = (function () { + + var ARR_EACH = Array.prototype.forEach; + var ARR_SLICE = Array.prototype.slice; + + /** + * Band-aid methods for things that should be a lot easier in JavaScript. + * Implementation and structure inspired by underscore.js + * http://documentcloud.github.com/underscore/ + */ + + return { + + BREAK: {}, + + extend: function(target) { + + this.each(ARR_SLICE.call(arguments, 1), function(obj) { + + for (var key in obj) + if (!this.isUndefined(obj[key])) + target[key] = obj[key]; + + }, this); + + return target; + + }, + + defaults: function(target) { + + this.each(ARR_SLICE.call(arguments, 1), function(obj) { + + for (var key in obj) + if (this.isUndefined(target[key])) + target[key] = obj[key]; + + }, this); + + return target; + + }, + + compose: function() { + var toCall = ARR_SLICE.call(arguments); + return function() { + var args = ARR_SLICE.call(arguments); + for (var i = toCall.length -1; i >= 0; i--) { + args = [toCall[i].apply(this, args)]; + } + return args[0]; + } + }, + + each: function(obj, itr, scope) { + + + if (ARR_EACH && obj.forEach === ARR_EACH) { + + obj.forEach(itr, scope); + + } else if (obj.length === obj.length + 0) { // Is number but not NaN + + for (var key = 0, l = obj.length; key < l; key++) + if (key in obj && itr.call(scope, obj[key], key) === this.BREAK) + return; + + } else { + + for (var key in obj) + if (itr.call(scope, obj[key], key) === this.BREAK) + return; + + } + + }, + + defer: function(fnc) { + setTimeout(fnc, 0); + }, + + toArray: function(obj) { + if (obj.toArray) return obj.toArray(); + return ARR_SLICE.call(obj); + }, + + isUndefined: function(obj) { + return obj === undefined; + }, + + isNull: function(obj) { + return obj === null; + }, + + isNaN: function(obj) { + return obj !== obj; + }, + + isArray: Array.isArray || function(obj) { + return obj.constructor === Array; + }, + + isObject: function(obj) { + return obj === Object(obj); + }, + + isNumber: function(obj) { + return obj === obj+0; + }, + + isString: function(obj) { + return obj === obj+''; + }, + + isBoolean: function(obj) { + return obj === false || obj === true; + }, + + isFunction: function(obj) { + return Object.prototype.toString.call(obj) === '[object Function]'; + } + + }; + +})(); + + +dat.controllers.Controller = (function (common) { + + /** + * @class An "abstract" class that represents a given property of an object. + * + * @param {Object} object The object to be manipulated + * @param {string} property The name of the property to be manipulated + * + * @member dat.controllers + */ + var Controller = function(object, property) { + + this.initialValue = object[property]; + + /** + * Those who extend this class will put their DOM elements in here. + * @type {DOMElement} + */ + this.domElement = document.createElement('div'); + + /** + * The object to manipulate + * @type {Object} + */ + this.object = object; + + /** + * The name of the property to manipulate + * @type {String} + */ + this.property = property; + + /** + * The function to be called on change. + * @type {Function} + * @ignore + */ + this.__onChange = undefined; + + /** + * The function to be called on finishing change. + * @type {Function} + * @ignore + */ + this.__onFinishChange = undefined; + + }; + + common.extend( + + Controller.prototype, + + /** @lends dat.controllers.Controller.prototype */ + { + + /** + * Specify that a function fire every time someone changes the value with + * this Controller. + * + * @param {Function} fnc This function will be called whenever the value + * is modified via this Controller. + * @returns {dat.controllers.Controller} this + */ + onChange: function(fnc) { + this.__onChange = fnc; + return this; + }, + + /** + * Specify that a function fire every time someone "finishes" changing + * the value wih this Controller. Useful for values that change + * incrementally like numbers or strings. + * + * @param {Function} fnc This function will be called whenever + * someone "finishes" changing the value via this Controller. + * @returns {dat.controllers.Controller} this + */ + onFinishChange: function(fnc) { + this.__onFinishChange = fnc; + return this; + }, + + /** + * Change the value of object[property] + * + * @param {Object} newValue The new value of object[property] + */ + setValue: function(newValue) { + this.object[this.property] = newValue; + if (this.__onChange) { + this.__onChange.call(this, newValue); + } + this.updateDisplay(); + return this; + }, + + /** + * Gets the value of object[property] + * + * @returns {Object} The current value of object[property] + */ + getValue: function() { + return this.object[this.property]; + }, + + /** + * Refreshes the visual display of a Controller in order to keep sync + * with the object's current value. + * @returns {dat.controllers.Controller} this + */ + updateDisplay: function() { + return this; + }, + + /** + * @returns {Boolean} true if the value has deviated from initialValue + */ + isModified: function() { + return this.initialValue !== this.getValue() + } + + } + + ); + + return Controller; + + +})(dat.utils.common); + + +dat.dom.dom = (function (common) { + + var EVENT_MAP = { + 'HTMLEvents': ['change'], + 'MouseEvents': ['click','mousemove','mousedown','mouseup', 'mouseover'], + 'KeyboardEvents': ['keydown'] + }; + + var EVENT_MAP_INV = {}; + common.each(EVENT_MAP, function(v, k) { + common.each(v, function(e) { + EVENT_MAP_INV[e] = k; + }); + }); + + var CSS_VALUE_PIXELS = /(\d+(\.\d+)?)px/; + + function cssValueToPixels(val) { + + if (val === '0' || common.isUndefined(val)) return 0; + + var match = val.match(CSS_VALUE_PIXELS); + + if (!common.isNull(match)) { + return parseFloat(match[1]); + } + + // TODO ...ems? %? + + return 0; + + } + + /** + * @namespace + * @member dat.dom + */ + var dom = { + + /** + * + * @param elem + * @param selectable + */ + makeSelectable: function(elem, selectable) { + + if (elem === undefined || elem.style === undefined) return; + + elem.onselectstart = selectable ? function() { + return false; + } : function() { + }; + + elem.style.MozUserSelect = selectable ? 'auto' : 'none'; + elem.style.KhtmlUserSelect = selectable ? 'auto' : 'none'; + elem.unselectable = selectable ? 'on' : 'off'; + + }, + + /** + * + * @param elem + * @param horizontal + * @param vertical + */ + makeFullscreen: function(elem, horizontal, vertical) { + + if (common.isUndefined(horizontal)) horizontal = true; + if (common.isUndefined(vertical)) vertical = true; + + elem.style.position = 'absolute'; + + if (horizontal) { + elem.style.left = 0; + elem.style.right = 0; + } + if (vertical) { + elem.style.top = 0; + elem.style.bottom = 0; + } + + }, + + /** + * + * @param elem + * @param eventType + * @param params + */ + fakeEvent: function(elem, eventType, params, aux) { + params = params || {}; + var className = EVENT_MAP_INV[eventType]; + if (!className) { + throw new Error('Event type ' + eventType + ' not supported.'); + } + var evt = document.createEvent(className); + switch (className) { + case 'MouseEvents': + var clientX = params.x || params.clientX || 0; + var clientY = params.y || params.clientY || 0; + evt.initMouseEvent(eventType, params.bubbles || false, + params.cancelable || true, window, params.clickCount || 1, + 0, //screen X + 0, //screen Y + clientX, //client X + clientY, //client Y + false, false, false, false, 0, null); + break; + case 'KeyboardEvents': + var init = evt.initKeyboardEvent || evt.initKeyEvent; // webkit || moz + common.defaults(params, { + cancelable: true, + ctrlKey: false, + altKey: false, + shiftKey: false, + metaKey: false, + keyCode: undefined, + charCode: undefined + }); + init(eventType, params.bubbles || false, + params.cancelable, window, + params.ctrlKey, params.altKey, + params.shiftKey, params.metaKey, + params.keyCode, params.charCode); + break; + default: + evt.initEvent(eventType, params.bubbles || false, + params.cancelable || true); + break; + } + common.defaults(evt, aux); + elem.dispatchEvent(evt); + }, + + /** + * + * @param elem + * @param event + * @param func + * @param bool + */ + bind: function(elem, event, func, bool) { + bool = bool || false; + if (elem.addEventListener) + elem.addEventListener(event, func, bool); + else if (elem.attachEvent) + elem.attachEvent('on' + event, func); + return dom; + }, + + /** + * + * @param elem + * @param event + * @param func + * @param bool + */ + unbind: function(elem, event, func, bool) { + bool = bool || false; + if (elem.removeEventListener) + elem.removeEventListener(event, func, bool); + else if (elem.detachEvent) + elem.detachEvent('on' + event, func); + return dom; + }, + + /** + * + * @param elem + * @param className + */ + addClass: function(elem, className) { + if (elem.className === undefined) { + elem.className = className; + } else if (elem.className !== className) { + var classes = elem.className.split(/ +/); + if (classes.indexOf(className) == -1) { + classes.push(className); + elem.className = classes.join(' ').replace(/^\s+/, '').replace(/\s+$/, ''); + } + } + return dom; + }, + + /** + * + * @param elem + * @param className + */ + removeClass: function(elem, className) { + if (className) { + if (elem.className === undefined) { + // elem.className = className; + } else if (elem.className === className) { + elem.removeAttribute('class'); + } else { + var classes = elem.className.split(/ +/); + var index = classes.indexOf(className); + if (index != -1) { + classes.splice(index, 1); + elem.className = classes.join(' '); + } + } + } else { + elem.className = undefined; + } + return dom; + }, + + hasClass: function(elem, className) { + return new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)').test(elem.className) || false; + }, + + /** + * + * @param elem + */ + getWidth: function(elem) { + + var style = getComputedStyle(elem); + + return cssValueToPixels(style['border-left-width']) + + cssValueToPixels(style['border-right-width']) + + cssValueToPixels(style['padding-left']) + + cssValueToPixels(style['padding-right']) + + cssValueToPixels(style['width']); + }, + + /** + * + * @param elem + */ + getHeight: function(elem) { + + var style = getComputedStyle(elem); + + return cssValueToPixels(style['border-top-width']) + + cssValueToPixels(style['border-bottom-width']) + + cssValueToPixels(style['padding-top']) + + cssValueToPixels(style['padding-bottom']) + + cssValueToPixels(style['height']); + }, + + /** + * + * @param elem + */ + getOffset: function(elem) { + var offset = {left: 0, top:0}; + if (elem.offsetParent) { + do { + offset.left += elem.offsetLeft; + offset.top += elem.offsetTop; + } while (elem = elem.offsetParent); + } + return offset; + }, + + // http://stackoverflow.com/posts/2684561/revisions + /** + * + * @param elem + */ + isActive: function(elem) { + return elem === document.activeElement && ( elem.type || elem.href ); + } + + }; + + return dom; + +})(dat.utils.common); + + +dat.controllers.OptionController = (function (Controller, dom, common) { + + /** + * @class Provides a select input to alter the property of an object, using a + * list of accepted values. + * + * @extends dat.controllers.Controller + * + * @param {Object} object The object to be manipulated + * @param {string} property The name of the property to be manipulated + * @param {Object|string[]} options A map of labels to acceptable values, or + * a list of acceptable string values. + * + * @member dat.controllers + */ + var OptionController = function(object, property, options) { + + OptionController.superclass.call(this, object, property); + + var _this = this; + + /** + * The drop down menu + * @ignore + */ + this.__select = document.createElement('select'); + + if (common.isArray(options)) { + var map = {}; + common.each(options, function(element) { + map[element] = element; + }); + options = map; + } + + common.each(options, function(value, key) { + + var opt = document.createElement('option'); + opt.innerHTML = key; + opt.setAttribute('value', value); + _this.__select.appendChild(opt); + + }); + + // Acknowledge original value + this.updateDisplay(); + + dom.bind(this.__select, 'change', function() { + var desiredValue = this.options[this.selectedIndex].value; + _this.setValue(desiredValue); + }); + + this.domElement.appendChild(this.__select); + + }; + + OptionController.superclass = Controller; + + common.extend( + + OptionController.prototype, + Controller.prototype, + + { + + setValue: function(v) { + var toReturn = OptionController.superclass.prototype.setValue.call(this, v); + if (this.__onFinishChange) { + this.__onFinishChange.call(this, this.getValue()); + } + return toReturn; + }, + + updateDisplay: function() { + this.__select.value = this.getValue(); + return OptionController.superclass.prototype.updateDisplay.call(this); + } + + } + + ); + + return OptionController; + +})(dat.controllers.Controller, +dat.dom.dom, +dat.utils.common); + + +dat.controllers.NumberController = (function (Controller, common) { + + /** + * @class Represents a given property of an object that is a number. + * + * @extends dat.controllers.Controller + * + * @param {Object} object The object to be manipulated + * @param {string} property The name of the property to be manipulated + * @param {Object} [params] Optional parameters + * @param {Number} [params.min] Minimum allowed value + * @param {Number} [params.max] Maximum allowed value + * @param {Number} [params.step] Increment by which to change value + * + * @member dat.controllers + */ + var NumberController = function(object, property, params) { + + NumberController.superclass.call(this, object, property); + + params = params || {}; + + this.__min = params.min; + this.__max = params.max; + this.__step = params.step; + + if (common.isUndefined(this.__step)) { + + if (this.initialValue == 0) { + this.__impliedStep = 1; // What are we, psychics? + } else { + // Hey Doug, check this out. + this.__impliedStep = Math.pow(10, Math.floor(Math.log(this.initialValue)/Math.LN10))/10; + } + + } else { + + this.__impliedStep = this.__step; + + } + + this.__precision = numDecimals(this.__impliedStep); + + + }; + + NumberController.superclass = Controller; + + common.extend( + + NumberController.prototype, + Controller.prototype, + + /** @lends dat.controllers.NumberController.prototype */ + { + + setValue: function(v) { + + if (this.__min !== undefined && v < this.__min) { + v = this.__min; + } else if (this.__max !== undefined && v > this.__max) { + v = this.__max; + } + + if (this.__step !== undefined && v % this.__step != 0) { + v = Math.round(v / this.__step) * this.__step; + } + + return NumberController.superclass.prototype.setValue.call(this, v); + + }, + + /** + * Specify a minimum value for object[property]. + * + * @param {Number} minValue The minimum value for + * object[property] + * @returns {dat.controllers.NumberController} this + */ + min: function(v) { + this.__min = v; + return this; + }, + + /** + * Specify a maximum value for object[property]. + * + * @param {Number} maxValue The maximum value for + * object[property] + * @returns {dat.controllers.NumberController} this + */ + max: function(v) { + this.__max = v; + return this; + }, + + /** + * Specify a step value that dat.controllers.NumberController + * increments by. + * + * @param {Number} stepValue The step value for + * dat.controllers.NumberController + * @default if minimum and maximum specified increment is 1% of the + * difference otherwise stepValue is 1 + * @returns {dat.controllers.NumberController} this + */ + step: function(v) { + this.__step = v; + return this; + } + + } + + ); + + function numDecimals(x) { + x = x.toString(); + if (x.indexOf('.') > -1) { + return x.length - x.indexOf('.') - 1; + } else { + return 0; + } + } + + return NumberController; + +})(dat.controllers.Controller, +dat.utils.common); + + +dat.controllers.NumberControllerBox = (function (NumberController, dom, common) { + + /** + * @class Represents a given property of an object that is a number and + * provides an input element with which to manipulate it. + * + * @extends dat.controllers.Controller + * @extends dat.controllers.NumberController + * + * @param {Object} object The object to be manipulated + * @param {string} property The name of the property to be manipulated + * @param {Object} [params] Optional parameters + * @param {Number} [params.min] Minimum allowed value + * @param {Number} [params.max] Maximum allowed value + * @param {Number} [params.step] Increment by which to change value + * + * @member dat.controllers + */ + var NumberControllerBox = function(object, property, params) { + + this.__truncationSuspended = false; + + NumberControllerBox.superclass.call(this, object, property, params); + + var _this = this; + + /** + * {Number} Previous mouse y position + * @ignore + */ + var prev_y; + + this.__input = document.createElement('input'); + this.__input.setAttribute('type', 'text'); + + // Makes it so manually specified values are not truncated. + + dom.bind(this.__input, 'change', onChange); + dom.bind(this.__input, 'blur', onBlur); + dom.bind(this.__input, 'mousedown', onMouseDown); + dom.bind(this.__input, 'keydown', function(e) { + + // When pressing entire, you can be as precise as you want. + if (e.keyCode === 13) { + _this.__truncationSuspended = true; + this.blur(); + _this.__truncationSuspended = false; + } + + }); + + function onChange() { + var attempted = parseFloat(_this.__input.value); + if (!common.isNaN(attempted)) _this.setValue(attempted); + } + + function onBlur() { + onChange(); + if (_this.__onFinishChange) { + _this.__onFinishChange.call(_this, _this.getValue()); + } + } + + function onMouseDown(e) { + dom.bind(window, 'mousemove', onMouseDrag); + dom.bind(window, 'mouseup', onMouseUp); + prev_y = e.clientY; + } + + function onMouseDrag(e) { + + var diff = prev_y - e.clientY; + _this.setValue(_this.getValue() + diff * _this.__impliedStep); + + prev_y = e.clientY; + + } + + function onMouseUp() { + dom.unbind(window, 'mousemove', onMouseDrag); + dom.unbind(window, 'mouseup', onMouseUp); + } + + this.updateDisplay(); + + this.domElement.appendChild(this.__input); + + }; + + NumberControllerBox.superclass = NumberController; + + common.extend( + + NumberControllerBox.prototype, + NumberController.prototype, + + { + + updateDisplay: function() { + + this.__input.value = this.__truncationSuspended ? this.getValue() : roundToDecimal(this.getValue(), this.__precision); + return NumberControllerBox.superclass.prototype.updateDisplay.call(this); + } + + } + + ); + + function roundToDecimal(value, decimals) { + var tenTo = Math.pow(10, decimals); + return Math.round(value * tenTo) / tenTo; + } + + return NumberControllerBox; + +})(dat.controllers.NumberController, +dat.dom.dom, +dat.utils.common); + + +dat.controllers.NumberControllerSlider = (function (NumberController, dom, css, common, styleSheet) { + + /** + * @class Represents a given property of an object that is a number, contains + * a minimum and maximum, and provides a slider element with which to + * manipulate it. It should be noted that the slider element is made up of + * <div> tags, not the html5 + * <slider> element. + * + * @extends dat.controllers.Controller + * @extends dat.controllers.NumberController + * + * @param {Object} object The object to be manipulated + * @param {string} property The name of the property to be manipulated + * @param {Number} minValue Minimum allowed value + * @param {Number} maxValue Maximum allowed value + * @param {Number} stepValue Increment by which to change value + * + * @member dat.controllers + */ + var NumberControllerSlider = function(object, property, min, max, step) { + + NumberControllerSlider.superclass.call(this, object, property, { min: min, max: max, step: step }); + + var _this = this; + + this.__background = document.createElement('div'); + this.__foreground = document.createElement('div'); + + + + dom.bind(this.__background, 'mousedown', onMouseDown); + + dom.addClass(this.__background, 'slider'); + dom.addClass(this.__foreground, 'slider-fg'); + + function onMouseDown(e) { + + dom.bind(window, 'mousemove', onMouseDrag); + dom.bind(window, 'mouseup', onMouseUp); + + onMouseDrag(e); + } + + function onMouseDrag(e) { + + e.preventDefault(); + + var offset = dom.getOffset(_this.__background); + var width = dom.getWidth(_this.__background); + + _this.setValue( + map(e.clientX, offset.left, offset.left + width, _this.__min, _this.__max) + ); + + return false; + + } + + function onMouseUp() { + dom.unbind(window, 'mousemove', onMouseDrag); + dom.unbind(window, 'mouseup', onMouseUp); + if (_this.__onFinishChange) { + _this.__onFinishChange.call(_this, _this.getValue()); + } + } + + this.updateDisplay(); + + this.__background.appendChild(this.__foreground); + this.domElement.appendChild(this.__background); + + }; + + NumberControllerSlider.superclass = NumberController; + + /** + * Injects default stylesheet for slider elements. + */ + NumberControllerSlider.useDefaultStyles = function() { + css.inject(styleSheet); + }; + + common.extend( + + NumberControllerSlider.prototype, + NumberController.prototype, + + { + + updateDisplay: function() { + var pct = (this.getValue() - this.__min)/(this.__max - this.__min); + this.__foreground.style.width = pct*100+'%'; + return NumberControllerSlider.superclass.prototype.updateDisplay.call(this); + } + + } + + + + ); + + function map(v, i1, i2, o1, o2) { + return o1 + (o2 - o1) * ((v - i1) / (i2 - i1)); + } + + return NumberControllerSlider; + +})(dat.controllers.NumberController, +dat.dom.dom, +dat.utils.css, +dat.utils.common, +".slider {\n box-shadow: inset 0 2px 4px rgba(0,0,0,0.15);\n height: 1em;\n border-radius: 1em;\n background-color: #eee;\n padding: 0 0.5em;\n overflow: hidden;\n}\n\n.slider-fg {\n padding: 1px 0 2px 0;\n background-color: #aaa;\n height: 1em;\n margin-left: -0.5em;\n padding-right: 0.5em;\n border-radius: 1em 0 0 1em;\n}\n\n.slider-fg:after {\n display: inline-block;\n border-radius: 1em;\n background-color: #fff;\n border: 1px solid #aaa;\n content: '';\n float: right;\n margin-right: -1em;\n margin-top: -1px;\n height: 0.9em;\n width: 0.9em;\n}"); + + +dat.controllers.FunctionController = (function (Controller, dom, common) { + + /** + * @class Provides a GUI interface to fire a specified method, a property of an object. + * + * @extends dat.controllers.Controller + * + * @param {Object} object The object to be manipulated + * @param {string} property The name of the property to be manipulated + * + * @member dat.controllers + */ + var FunctionController = function(object, property, text) { + + FunctionController.superclass.call(this, object, property); + + var _this = this; + + this.__button = document.createElement('div'); + this.__button.innerHTML = text === undefined ? 'Fire' : text; + dom.bind(this.__button, 'click', function(e) { + e.preventDefault(); + _this.fire(); + return false; + }); + + dom.addClass(this.__button, 'button'); + + this.domElement.appendChild(this.__button); + + + }; + + FunctionController.superclass = Controller; + + common.extend( + + FunctionController.prototype, + Controller.prototype, + { + + fire: function() { + if (this.__onChange) { + this.__onChange.call(this); + } + if (this.__onFinishChange) { + this.__onFinishChange.call(this, this.getValue()); + } + this.getValue().call(this.object); + } + } + + ); + + return FunctionController; + +})(dat.controllers.Controller, +dat.dom.dom, +dat.utils.common); + + +dat.controllers.BooleanController = (function (Controller, dom, common) { + + /** + * @class Provides a checkbox input to alter the boolean property of an object. + * @extends dat.controllers.Controller + * + * @param {Object} object The object to be manipulated + * @param {string} property The name of the property to be manipulated + * + * @member dat.controllers + */ + var BooleanController = function(object, property) { + + BooleanController.superclass.call(this, object, property); + + var _this = this; + this.__prev = this.getValue(); + + this.__checkbox = document.createElement('input'); + this.__checkbox.setAttribute('type', 'checkbox'); + + + dom.bind(this.__checkbox, 'change', onChange, false); + + this.domElement.appendChild(this.__checkbox); + + // Match original value + this.updateDisplay(); + + function onChange() { + _this.setValue(!_this.__prev); + } + + }; + + BooleanController.superclass = Controller; + + common.extend( + + BooleanController.prototype, + Controller.prototype, + + { + + setValue: function(v) { + var toReturn = BooleanController.superclass.prototype.setValue.call(this, v); + if (this.__onFinishChange) { + this.__onFinishChange.call(this, this.getValue()); + } + this.__prev = this.getValue(); + return toReturn; + }, + + updateDisplay: function() { + + if (this.getValue() === true) { + this.__checkbox.setAttribute('checked', 'checked'); + this.__checkbox.checked = true; + } else { + this.__checkbox.checked = false; + } + + return BooleanController.superclass.prototype.updateDisplay.call(this); + + } + + + } + + ); + + return BooleanController; + +})(dat.controllers.Controller, +dat.dom.dom, +dat.utils.common); + + +dat.color.toString = (function (common) { + + return function(color) { + + if (color.a == 1 || common.isUndefined(color.a)) { + + var s = color.hex.toString(16); + while (s.length < 6) { + s = '0' + s; + } + + return '#' + s; + + } else { + + return 'rgba(' + Math.round(color.r) + ',' + Math.round(color.g) + ',' + Math.round(color.b) + ',' + color.a + ')'; + + } + + } + +})(dat.utils.common); + + +dat.color.interpret = (function (toString, common) { + + var result, toReturn; + + var interpret = function() { + + toReturn = false; + + var original = arguments.length > 1 ? common.toArray(arguments) : arguments[0]; + + common.each(INTERPRETATIONS, function(family) { + + if (family.litmus(original)) { + + common.each(family.conversions, function(conversion, conversionName) { + + result = conversion.read(original); + + if (toReturn === false && result !== false) { + toReturn = result; + result.conversionName = conversionName; + result.conversion = conversion; + return common.BREAK; + + } + + }); + + return common.BREAK; + + } + + }); + + return toReturn; + + }; + + var INTERPRETATIONS = [ + + // Strings + { + + litmus: common.isString, + + conversions: { + + THREE_CHAR_HEX: { + + read: function(original) { + + var test = original.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i); + if (test === null) return false; + + return { + space: 'HEX', + hex: parseInt( + '0x' + + test[1].toString() + test[1].toString() + + test[2].toString() + test[2].toString() + + test[3].toString() + test[3].toString()) + }; + + }, + + write: toString + + }, + + SIX_CHAR_HEX: { + + read: function(original) { + + var test = original.match(/^#([A-F0-9]{6})$/i); + if (test === null) return false; + + return { + space: 'HEX', + hex: parseInt('0x' + test[1].toString()) + }; + + }, + + write: toString + + }, + + CSS_RGB: { + + read: function(original) { + + var test = original.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/); + if (test === null) return false; + + return { + space: 'RGB', + r: parseFloat(test[1]), + g: parseFloat(test[2]), + b: parseFloat(test[3]) + }; + + }, + + write: toString + + }, + + CSS_RGBA: { + + read: function(original) { + + var test = original.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\,\s*(.+)\s*\)/); + if (test === null) return false; + + return { + space: 'RGB', + r: parseFloat(test[1]), + g: parseFloat(test[2]), + b: parseFloat(test[3]), + a: parseFloat(test[4]) + }; + + }, + + write: toString + + } + + } + + }, + + // Numbers + { + + litmus: common.isNumber, + + conversions: { + + HEX: { + read: function(original) { + return { + space: 'HEX', + hex: original, + conversionName: 'HEX' + } + }, + + write: function(color) { + return color.hex; + } + } + + } + + }, + + // Arrays + { + + litmus: common.isArray, + + conversions: { + + RGB_ARRAY: { + read: function(original) { + if (original.length != 3) return false; + return { + space: 'RGB', + r: original[0], + g: original[1], + b: original[2] + }; + }, + + write: function(color) { + return [color.r, color.g, color.b]; + } + + }, + + RGBA_ARRAY: { + read: function(original) { + if (original.length != 4) return false; + return { + space: 'RGB', + r: original[0], + g: original[1], + b: original[2], + a: original[3] + }; + }, + + write: function(color) { + return [color.r, color.g, color.b, color.a]; + } + + } + + } + + }, + + // Objects + { + + litmus: common.isObject, + + conversions: { + + RGBA_OBJ: { + read: function(original) { + if (common.isNumber(original.r) && + common.isNumber(original.g) && + common.isNumber(original.b) && + common.isNumber(original.a)) { + return { + space: 'RGB', + r: original.r, + g: original.g, + b: original.b, + a: original.a + } + } + return false; + }, + + write: function(color) { + return { + r: color.r, + g: color.g, + b: color.b, + a: color.a + } + } + }, + + RGB_OBJ: { + read: function(original) { + if (common.isNumber(original.r) && + common.isNumber(original.g) && + common.isNumber(original.b)) { + return { + space: 'RGB', + r: original.r, + g: original.g, + b: original.b + } + } + return false; + }, + + write: function(color) { + return { + r: color.r, + g: color.g, + b: color.b + } + } + }, + + HSVA_OBJ: { + read: function(original) { + if (common.isNumber(original.h) && + common.isNumber(original.s) && + common.isNumber(original.v) && + common.isNumber(original.a)) { + return { + space: 'HSV', + h: original.h, + s: original.s, + v: original.v, + a: original.a + } + } + return false; + }, + + write: function(color) { + return { + h: color.h, + s: color.s, + v: color.v, + a: color.a + } + } + }, + + HSV_OBJ: { + read: function(original) { + if (common.isNumber(original.h) && + common.isNumber(original.s) && + common.isNumber(original.v)) { + return { + space: 'HSV', + h: original.h, + s: original.s, + v: original.v + } + } + return false; + }, + + write: function(color) { + return { + h: color.h, + s: color.s, + v: color.v + } + } + + } + + } + + } + + + ]; + + return interpret; + + +})(dat.color.toString, +dat.utils.common); + + +dat.GUI = dat.gui.GUI = (function (css, saveDialogueContents, styleSheet, controllerFactory, Controller, BooleanController, FunctionController, NumberControllerBox, NumberControllerSlider, OptionController, ColorController, requestAnimationFrame, CenteredDiv, dom, common) { + + css.inject(styleSheet); + + /** Outer-most className for GUI's */ + var CSS_NAMESPACE = 'dg'; + + var HIDE_KEY_CODE = 72; + + /** The only value shared between the JS and SCSS. Use caution. */ + var CLOSE_BUTTON_HEIGHT = 20; + + var DEFAULT_DEFAULT_PRESET_NAME = 'Default'; + + var SUPPORTS_LOCAL_STORAGE = (function() { + try { + return 'localStorage' in window && window['localStorage'] !== null; + } catch (e) { + return false; + } + })(); + + var SAVE_DIALOGUE; + + /** Have we yet to create an autoPlace GUI? */ + var auto_place_virgin = true; + + /** Fixed position div that auto place GUI's go inside */ + var auto_place_container; + + /** Are we hiding the GUI's ? */ + var hide = false; + + /** GUI's which should be hidden */ + var hideable_guis = []; + + /** + * A lightweight controller library for JavaScript. It allows you to easily + * manipulate variables and fire functions on the fly. + * @class + * + * @member dat.gui + * + * @param {Object} [params] + * @param {String} [params.name] The name of this GUI. + * @param {Object} [params.load] JSON object representing the saved state of + * this GUI. + * @param {Boolean} [params.auto=true] + * @param {dat.gui.GUI} [params.parent] The GUI I'm nested in. + * @param {Boolean} [params.closed] If true, starts closed + */ + var GUI = function(params) { + + var _this = this; + + /** + * Outermost DOM Element + * @type DOMElement + */ + this.domElement = document.createElement('div'); + this.__ul = document.createElement('ul'); + this.domElement.appendChild(this.__ul); + + dom.addClass(this.domElement, CSS_NAMESPACE); + + /** + * Nested GUI's by name + * @ignore + */ + this.__folders = {}; + + this.__controllers = []; + + /** + * List of objects I'm remembering for save, only used in top level GUI + * @ignore + */ + this.__rememberedObjects = []; + + /** + * Maps the index of remembered objects to a map of controllers, only used + * in top level GUI. + * + * @private + * @ignore + * + * @example + * [ + * { + * propertyName: Controller, + * anotherPropertyName: Controller + * }, + * { + * propertyName: Controller + * } + * ] + */ + this.__rememberedObjectIndecesToControllers = []; + + this.__listening = []; + + params = params || {}; + + // Default parameters + params = common.defaults(params, { + autoPlace: true, + width: GUI.DEFAULT_WIDTH + }); + + params = common.defaults(params, { + resizable: params.autoPlace, + hideable: params.autoPlace + }); + + + if (!common.isUndefined(params.load)) { + + // Explicit preset + if (params.preset) params.load.preset = params.preset; + + } else { + + params.load = { preset: DEFAULT_DEFAULT_PRESET_NAME }; + + } + + if (common.isUndefined(params.parent) && params.hideable) { + hideable_guis.push(this); + } + + // Only root level GUI's are resizable. + params.resizable = common.isUndefined(params.parent) && params.resizable; + + + if (params.autoPlace && common.isUndefined(params.scrollable)) { + params.scrollable = true; + } +// params.scrollable = common.isUndefined(params.parent) && params.scrollable === true; + + // Not part of params because I don't want people passing this in via + // constructor. Should be a 'remembered' value. + var use_local_storage = + SUPPORTS_LOCAL_STORAGE && + localStorage.getItem(getLocalStorageHash(this, 'isLocal')) === 'true'; + + Object.defineProperties(this, + + /** @lends dat.gui.GUI.prototype */ + { + + /** + * The parent GUI + * @type dat.gui.GUI + */ + parent: { + get: function() { + return params.parent; + } + }, + + scrollable: { + get: function() { + return params.scrollable; + } + }, + + /** + * Handles GUI's element placement for you + * @type Boolean + */ + autoPlace: { + get: function() { + return params.autoPlace; + } + }, + + /** + * The identifier for a set of saved values + * @type String + */ + preset: { + + get: function() { + if (_this.parent) { + return _this.getRoot().preset; + } else { + return params.load.preset; + } + }, + + set: function(v) { + if (_this.parent) { + _this.getRoot().preset = v; + } else { + params.load.preset = v; + } + setPresetSelectIndex(this); + _this.revert(); + } + + }, + + /** + * The width of GUI element + * @type Number + */ + width: { + get: function() { + return params.width; + }, + set: function(v) { + params.width = v; + setWidth(_this, v); + } + }, + + /** + * The name of GUI. Used for folders. i.e + * a folder's name + * @type String + */ + name: { + get: function() { + return params.name; + }, + set: function(v) { + // TODO Check for collisions among sibling folders + params.name = v; + if (title_row_name) { + title_row_name.innerHTML = params.name; + } + } + }, + + /** + * Whether the GUI is collapsed or not + * @type Boolean + */ + closed: { + get: function() { + return params.closed; + }, + set: function(v) { + params.closed = v; + if (params.closed) { + dom.addClass(_this.__ul, GUI.CLASS_CLOSED); + } else { + dom.removeClass(_this.__ul, GUI.CLASS_CLOSED); + } + // For browsers that aren't going to respect the CSS transition, + // Lets just check our height against the window height right off + // the bat. + this.onResize(); + + if (_this.__closeButton) { + _this.__closeButton.innerHTML = v ? GUI.TEXT_OPEN : GUI.TEXT_CLOSED; + } + } + }, + + /** + * Contains all presets + * @type Object + */ + load: { + get: function() { + return params.load; + } + }, + + /** + * Determines whether or not to use localStorage as the means for + * remembering + * @type Boolean + */ + useLocalStorage: { + + get: function() { + return use_local_storage; + }, + set: function(bool) { + if (SUPPORTS_LOCAL_STORAGE) { + use_local_storage = bool; + if (bool) { + dom.bind(window, 'unload', saveToLocalStorage); + } else { + dom.unbind(window, 'unload', saveToLocalStorage); + } + localStorage.setItem(getLocalStorageHash(_this, 'isLocal'), bool); + } + } + + } + + }); + + // Are we a root level GUI? + if (common.isUndefined(params.parent)) { + + params.closed = false; + + dom.addClass(this.domElement, GUI.CLASS_MAIN); + dom.makeSelectable(this.domElement, false); + + // Are we supposed to be loading locally? + if (SUPPORTS_LOCAL_STORAGE) { + + if (use_local_storage) { + + _this.useLocalStorage = true; + + var saved_gui = localStorage.getItem(getLocalStorageHash(this, 'gui')); + + if (saved_gui) { + params.load = JSON.parse(saved_gui); + } + + } + + } + + this.__closeButton = document.createElement('div'); + this.__closeButton.innerHTML = GUI.TEXT_CLOSED; + dom.addClass(this.__closeButton, GUI.CLASS_CLOSE_BUTTON); + this.domElement.appendChild(this.__closeButton); + + dom.bind(this.__closeButton, 'click', function() { + + _this.closed = !_this.closed; + + + }); + + + // Oh, you're a nested GUI! + } else { + + if (params.closed === undefined) { + params.closed = true; + } + + var title_row_name = document.createTextNode(params.name); + dom.addClass(title_row_name, 'controller-name'); + + var title_row = addRow(_this, title_row_name); + + var on_click_title = function(e) { + e.preventDefault(); + _this.closed = !_this.closed; + return false; + }; + + dom.addClass(this.__ul, GUI.CLASS_CLOSED); + + dom.addClass(title_row, 'title'); + dom.bind(title_row, 'click', on_click_title); + + if (!params.closed) { + this.closed = false; + } + + } + + if (params.autoPlace) { + + if (common.isUndefined(params.parent)) { + + if (auto_place_virgin) { + auto_place_container = document.createElement('div'); + dom.addClass(auto_place_container, CSS_NAMESPACE); + dom.addClass(auto_place_container, GUI.CLASS_AUTO_PLACE_CONTAINER); + document.body.appendChild(auto_place_container); + auto_place_virgin = false; + } + + // Put it in the dom for you. + auto_place_container.appendChild(this.domElement); + + // Apply the auto styles + dom.addClass(this.domElement, GUI.CLASS_AUTO_PLACE); + + } + + + // Make it not elastic. + if (!this.parent) setWidth(_this, params.width); + + } + + dom.bind(window, 'resize', function() { _this.onResize() }); + dom.bind(this.__ul, 'webkitTransitionEnd', function() { _this.onResize(); }); + dom.bind(this.__ul, 'transitionend', function() { _this.onResize() }); + dom.bind(this.__ul, 'oTransitionEnd', function() { _this.onResize() }); + this.onResize(); + + + if (params.resizable) { + addResizeHandle(this); + } + + function saveToLocalStorage() { + localStorage.setItem(getLocalStorageHash(_this, 'gui'), JSON.stringify(_this.getSaveObject())); + } + + var root = _this.getRoot(); + function resetWidth() { + var root = _this.getRoot(); + root.width += 1; + common.defer(function() { + root.width -= 1; + }); + } + + if (!params.parent) { + resetWidth(); + } + + }; + + GUI.toggleHide = function() { + + hide = !hide; + common.each(hideable_guis, function(gui) { + gui.domElement.style.zIndex = hide ? -999 : 999; + gui.domElement.style.opacity = hide ? 0 : 1; + }); + }; + + GUI.CLASS_AUTO_PLACE = 'a'; + GUI.CLASS_AUTO_PLACE_CONTAINER = 'ac'; + GUI.CLASS_MAIN = 'main'; + GUI.CLASS_CONTROLLER_ROW = 'cr'; + GUI.CLASS_TOO_TALL = 'taller-than-window'; + GUI.CLASS_CLOSED = 'closed'; + GUI.CLASS_CLOSE_BUTTON = 'close-button'; + GUI.CLASS_DRAG = 'drag'; + + GUI.DEFAULT_WIDTH = 245; + GUI.TEXT_CLOSED = 'Close Controls'; + GUI.TEXT_OPEN = 'Open Controls'; + + dom.bind(window, 'keydown', function(e) { + + if (document.activeElement.type !== 'text' && + (e.which === HIDE_KEY_CODE || e.keyCode == HIDE_KEY_CODE)) { + GUI.toggleHide(); + } + + }, false); + + common.extend( + + GUI.prototype, + + /** @lends dat.gui.GUI */ + { + + /** + * @param object + * @param property + * @returns {dat.controllers.Controller} The new controller that was added. + * @instance + */ + add: function(object, property) { + + return add( + this, + object, + property, + { + factoryArgs: Array.prototype.slice.call(arguments, 2) + } + ); + + }, + + /** + * @param object + * @param property + * @returns {dat.controllers.ColorController} The new controller that was added. + * @instance + */ + addColor: function(object, property) { + + return add( + this, + object, + property, + { + color: true + } + ); + + }, + + /** + * @param controller + * @instance + */ + remove: function(controller) { + + // TODO listening? + this.__ul.removeChild(controller.__li); + this.__controllers.slice(this.__controllers.indexOf(controller), 1); + var _this = this; + common.defer(function() { + _this.onResize(); + }); + + }, + + destroy: function() { + + if (this.autoPlace) { + auto_place_container.removeChild(this.domElement); + } + + }, + + /** + * @param name + * @returns {dat.gui.GUI} The new folder. + * @throws {Error} if this GUI already has a folder by the specified + * name + * @instance + */ + addFolder: function(name) { + + // We have to prevent collisions on names in order to have a key + // by which to remember saved values + if (this.__folders[name] !== undefined) { + throw new Error('You already have a folder in this GUI by the' + + ' name "' + name + '"'); + } + + var new_gui_params = { name: name, parent: this }; + + // We need to pass down the autoPlace trait so that we can + // attach event listeners to open/close folder actions to + // ensure that a scrollbar appears if the window is too short. + new_gui_params.autoPlace = this.autoPlace; + + // Do we have saved appearance data for this folder? + + if (this.load && // Anything loaded? + this.load.folders && // Was my parent a dead-end? + this.load.folders[name]) { // Did daddy remember me? + + // Start me closed if I was closed + new_gui_params.closed = this.load.folders[name].closed; + + // Pass down the loaded data + new_gui_params.load = this.load.folders[name]; + + } + + var gui = new GUI(new_gui_params); + this.__folders[name] = gui; + + var li = addRow(this, gui.domElement); + dom.addClass(li, 'folder'); + return gui; + + }, + + open: function() { + this.closed = false; + }, + + close: function() { + this.closed = true; + }, + + onResize: function() { + + var root = this.getRoot(); + + if (root.scrollable) { + + var top = dom.getOffset(root.__ul).top; + var h = 0; + + common.each(root.__ul.childNodes, function(node) { + if (! (root.autoPlace && node === root.__save_row)) + h += dom.getHeight(node); + }); + + if (window.innerHeight - top - CLOSE_BUTTON_HEIGHT < h) { + dom.addClass(root.domElement, GUI.CLASS_TOO_TALL); + root.__ul.style.height = window.innerHeight - top - CLOSE_BUTTON_HEIGHT + 'px'; + } else { + dom.removeClass(root.domElement, GUI.CLASS_TOO_TALL); + root.__ul.style.height = 'auto'; + } + + } + + if (root.__resize_handle) { + common.defer(function() { + root.__resize_handle.style.height = root.__ul.offsetHeight + 'px'; + }); + } + + if (root.__closeButton) { + root.__closeButton.style.width = root.width + 'px'; + } + + }, + + /** + * Mark objects for saving. The order of these objects cannot change as + * the GUI grows. When remembering new objects, append them to the end + * of the list. + * + * @param {Object...} objects + * @throws {Error} if not called on a top level GUI. + * @instance + */ + remember: function() { + + if (common.isUndefined(SAVE_DIALOGUE)) { + SAVE_DIALOGUE = new CenteredDiv(); + SAVE_DIALOGUE.domElement.innerHTML = saveDialogueContents; + } + + if (this.parent) { + throw new Error("You can only call remember on a top level GUI."); + } + + var _this = this; + + common.each(Array.prototype.slice.call(arguments), function(object) { + if (_this.__rememberedObjects.length == 0) { + addSaveMenu(_this); + } + if (_this.__rememberedObjects.indexOf(object) == -1) { + _this.__rememberedObjects.push(object); + } + }); + + if (this.autoPlace) { + // Set save row width + setWidth(this, this.width); + } + + }, + + /** + * @returns {dat.gui.GUI} the topmost parent GUI of a nested GUI. + * @instance + */ + getRoot: function() { + var gui = this; + while (gui.parent) { + gui = gui.parent; + } + return gui; + }, + + /** + * @returns {Object} a JSON object representing the current state of + * this GUI as well as its remembered properties. + * @instance + */ + getSaveObject: function() { + + var toReturn = this.load; + + toReturn.closed = this.closed; + + // Am I remembering any values? + if (this.__rememberedObjects.length > 0) { + + toReturn.preset = this.preset; + + if (!toReturn.remembered) { + toReturn.remembered = {}; + } + + toReturn.remembered[this.preset] = getCurrentPreset(this); + + } + + toReturn.folders = {}; + common.each(this.__folders, function(element, key) { + toReturn.folders[key] = element.getSaveObject(); + }); + + return toReturn; + + }, + + save: function() { + + if (!this.load.remembered) { + this.load.remembered = {}; + } + + this.load.remembered[this.preset] = getCurrentPreset(this); + markPresetModified(this, false); + + }, + + saveAs: function(presetName) { + + if (!this.load.remembered) { + + // Retain default values upon first save + this.load.remembered = {}; + this.load.remembered[DEFAULT_DEFAULT_PRESET_NAME] = getCurrentPreset(this, true); + + } + + this.load.remembered[presetName] = getCurrentPreset(this); + this.preset = presetName; + addPresetOption(this, presetName, true); + + }, + + revert: function(gui) { + + common.each(this.__controllers, function(controller) { + // Make revert work on Default. + if (!this.getRoot().load.remembered) { + controller.setValue(controller.initialValue); + } else { + recallSavedValue(gui || this.getRoot(), controller); + } + }, this); + + common.each(this.__folders, function(folder) { + folder.revert(folder); + }); + + if (!gui) { + markPresetModified(this.getRoot(), false); + } + + + }, + + listen: function(controller) { + + var init = this.__listening.length == 0; + this.__listening.push(controller); + if (init) updateDisplays(this.__listening); + + } + + } + + ); + + function add(gui, object, property, params) { + + if (object[property] === undefined) { + throw new Error("Object " + object + " has no property \"" + property + "\""); + } + + var controller; + + if (params.color) { + + controller = new ColorController(object, property); + + } else { + + var factoryArgs = [object,property].concat(params.factoryArgs); + controller = controllerFactory.apply(gui, factoryArgs); + + } + + if (params.before instanceof Controller) { + params.before = params.before.__li; + } + + recallSavedValue(gui, controller); + + dom.addClass(controller.domElement, 'c'); + + var name = document.createElement('span'); + dom.addClass(name, 'property-name'); + name.innerHTML = controller.property; + + var container = document.createElement('div'); + container.appendChild(name); + container.appendChild(controller.domElement); + + var li = addRow(gui, container, params.before); + + dom.addClass(li, GUI.CLASS_CONTROLLER_ROW); + dom.addClass(li, typeof controller.getValue()); + + augmentController(gui, li, controller); + + gui.__controllers.push(controller); + + return controller; + + } + + /** + * Add a row to the end of the GUI or before another row. + * + * @param gui + * @param [dom] If specified, inserts the dom content in the new row + * @param [liBefore] If specified, places the new row before another row + */ + function addRow(gui, dom, liBefore) { + var li = document.createElement('li'); + if (dom) li.appendChild(dom); + if (liBefore) { + gui.__ul.insertBefore(li, params.before); + } else { + gui.__ul.appendChild(li); + } + gui.onResize(); + return li; + } + + function augmentController(gui, li, controller) { + + controller.__li = li; + controller.__gui = gui; + + common.extend(controller, { + + options: function(options) { + + if (arguments.length > 1) { + controller.remove(); + + return add( + gui, + controller.object, + controller.property, + { + before: controller.__li.nextElementSibling, + factoryArgs: [common.toArray(arguments)] + } + ); + + } + + if (common.isArray(options) || common.isObject(options)) { + controller.remove(); + + return add( + gui, + controller.object, + controller.property, + { + before: controller.__li.nextElementSibling, + factoryArgs: [options] + } + ); + + } + + }, + + name: function(v) { + controller.__li.firstElementChild.firstElementChild.innerHTML = v; + return controller; + }, + + listen: function() { + controller.__gui.listen(controller); + return controller; + }, + + remove: function() { + controller.__gui.remove(controller); + return controller; + } + + }); + + // All sliders should be accompanied by a box. + if (controller instanceof NumberControllerSlider) { + + var box = new NumberControllerBox(controller.object, controller.property, + { min: controller.__min, max: controller.__max, step: controller.__step }); + + common.each(['updateDisplay', 'onChange', 'onFinishChange'], function(method) { + var pc = controller[method]; + var pb = box[method]; + controller[method] = box[method] = function() { + var args = Array.prototype.slice.call(arguments); + pc.apply(controller, args); + return pb.apply(box, args); + } + }); + + dom.addClass(li, 'has-slider'); + controller.domElement.insertBefore(box.domElement, controller.domElement.firstElementChild); + + } + else if (controller instanceof NumberControllerBox) { + + var r = function(returned) { + + // Have we defined both boundaries? + if (common.isNumber(controller.__min) && common.isNumber(controller.__max)) { + + // Well, then lets just replace this with a slider. + controller.remove(); + return add( + gui, + controller.object, + controller.property, + { + before: controller.__li.nextElementSibling, + factoryArgs: [controller.__min, controller.__max, controller.__step] + }); + + } + + return returned; + + }; + + controller.min = common.compose(r, controller.min); + controller.max = common.compose(r, controller.max); + + } + else if (controller instanceof BooleanController) { + + dom.bind(li, 'click', function() { + dom.fakeEvent(controller.__checkbox, 'click'); + }); + + dom.bind(controller.__checkbox, 'click', function(e) { + e.stopPropagation(); // Prevents double-toggle + }) + + } + else if (controller instanceof FunctionController) { + + dom.bind(li, 'click', function() { + dom.fakeEvent(controller.__button, 'click'); + }); + + dom.bind(li, 'mouseover', function() { + dom.addClass(controller.__button, 'hover'); + }); + + dom.bind(li, 'mouseout', function() { + dom.removeClass(controller.__button, 'hover'); + }); + + } + else if (controller instanceof ColorController) { + + dom.addClass(li, 'color'); + controller.updateDisplay = common.compose(function(r) { + li.style.borderLeftColor = controller.__color.toString(); + return r; + }, controller.updateDisplay); + + controller.updateDisplay(); + + } + + controller.setValue = common.compose(function(r) { + if (gui.getRoot().__preset_select && controller.isModified()) { + markPresetModified(gui.getRoot(), true); + } + return r; + }, controller.setValue); + + } + + function recallSavedValue(gui, controller) { + + // Find the topmost GUI, that's where remembered objects live. + var root = gui.getRoot(); + + // Does the object we're controlling match anything we've been told to + // remember? + var matched_index = root.__rememberedObjects.indexOf(controller.object); + + // Why yes, it does! + if (matched_index != -1) { + + // Let me fetch a map of controllers for thcommon.isObject. + var controller_map = + root.__rememberedObjectIndecesToControllers[matched_index]; + + // Ohp, I believe this is the first controller we've created for this + // object. Lets make the map fresh. + if (controller_map === undefined) { + controller_map = {}; + root.__rememberedObjectIndecesToControllers[matched_index] = + controller_map; + } + + // Keep track of this controller + controller_map[controller.property] = controller; + + // Okay, now have we saved any values for this controller? + if (root.load && root.load.remembered) { + + var preset_map = root.load.remembered; + + // Which preset are we trying to load? + var preset; + + if (preset_map[gui.preset]) { + + preset = preset_map[gui.preset]; + + } else if (preset_map[DEFAULT_DEFAULT_PRESET_NAME]) { + + // Uhh, you can have the default instead? + preset = preset_map[DEFAULT_DEFAULT_PRESET_NAME]; + + } else { + + // Nada. + + return; + + } + + + // Did the loaded object remember thcommon.isObject? + if (preset[matched_index] && + + // Did we remember this particular property? + preset[matched_index][controller.property] !== undefined) { + + // We did remember something for this guy ... + var value = preset[matched_index][controller.property]; + + // And that's what it is. + controller.initialValue = value; + controller.setValue(value); + + } + + } + + } + + } + + function getLocalStorageHash(gui, key) { + // TODO how does this deal with multiple GUI's? + return document.location.href + '.' + key; + + } + + function addSaveMenu(gui) { + + var div = gui.__save_row = document.createElement('li'); + + dom.addClass(gui.domElement, 'has-save'); + + gui.__ul.insertBefore(div, gui.__ul.firstChild); + + dom.addClass(div, 'save-row'); + + var gears = document.createElement('span'); + gears.innerHTML = ' '; + dom.addClass(gears, 'button gears'); + + // TODO replace with FunctionController + var button = document.createElement('span'); + button.innerHTML = 'Save'; + dom.addClass(button, 'button'); + dom.addClass(button, 'save'); + + var button2 = document.createElement('span'); + button2.innerHTML = 'New'; + dom.addClass(button2, 'button'); + dom.addClass(button2, 'save-as'); + + var button3 = document.createElement('span'); + button3.innerHTML = 'Revert'; + dom.addClass(button3, 'button'); + dom.addClass(button3, 'revert'); + + var select = gui.__preset_select = document.createElement('select'); + + if (gui.load && gui.load.remembered) { + + common.each(gui.load.remembered, function(value, key) { + addPresetOption(gui, key, key == gui.preset); + }); + + } else { + addPresetOption(gui, DEFAULT_DEFAULT_PRESET_NAME, false); + } + + dom.bind(select, 'change', function() { + + + for (var index = 0; index < gui.__preset_select.length; index++) { + gui.__preset_select[index].innerHTML = gui.__preset_select[index].value; + } + + gui.preset = this.value; + + }); + + div.appendChild(select); + div.appendChild(gears); + div.appendChild(button); + div.appendChild(button2); + div.appendChild(button3); + + if (SUPPORTS_LOCAL_STORAGE) { + + var saveLocally = document.getElementById('dg-save-locally'); + var explain = document.getElementById('dg-local-explain'); + + saveLocally.style.display = 'block'; + + var localStorageCheckBox = document.getElementById('dg-local-storage'); + + if (localStorage.getItem(getLocalStorageHash(gui, 'isLocal')) === 'true') { + localStorageCheckBox.setAttribute('checked', 'checked'); + } + + function showHideExplain() { + explain.style.display = gui.useLocalStorage ? 'block' : 'none'; + } + + showHideExplain(); + + // TODO: Use a boolean controller, fool! + dom.bind(localStorageCheckBox, 'change', function() { + gui.useLocalStorage = !gui.useLocalStorage; + showHideExplain(); + }); + + } + + var newConstructorTextArea = document.getElementById('dg-new-constructor'); + + dom.bind(newConstructorTextArea, 'keydown', function(e) { + if (e.metaKey && (e.which === 67 || e.keyCode == 67)) { + SAVE_DIALOGUE.hide(); + } + }); + + dom.bind(gears, 'click', function() { + newConstructorTextArea.innerHTML = JSON.stringify(gui.getSaveObject(), undefined, 2); + SAVE_DIALOGUE.show(); + newConstructorTextArea.focus(); + newConstructorTextArea.select(); + }); + + dom.bind(button, 'click', function() { + gui.save(); + }); + + dom.bind(button2, 'click', function() { + var presetName = prompt('Enter a new preset name.'); + if (presetName) gui.saveAs(presetName); + }); + + dom.bind(button3, 'click', function() { + gui.revert(); + }); + +// div.appendChild(button2); + + } + + function addResizeHandle(gui) { + + gui.__resize_handle = document.createElement('div'); + + common.extend(gui.__resize_handle.style, { + + width: '6px', + marginLeft: '-3px', + height: '200px', + cursor: 'ew-resize', + position: 'absolute' +// border: '1px solid blue' + + }); + + var pmouseX; + + dom.bind(gui.__resize_handle, 'mousedown', dragStart); + dom.bind(gui.__closeButton, 'mousedown', dragStart); + + gui.domElement.insertBefore(gui.__resize_handle, gui.domElement.firstElementChild); + + function dragStart(e) { + + e.preventDefault(); + + pmouseX = e.clientX; + + dom.addClass(gui.__closeButton, GUI.CLASS_DRAG); + dom.bind(window, 'mousemove', drag); + dom.bind(window, 'mouseup', dragStop); + + return false; + + } + + function drag(e) { + + e.preventDefault(); + + gui.width += pmouseX - e.clientX; + gui.onResize(); + pmouseX = e.clientX; + + return false; + + } + + function dragStop() { + + dom.removeClass(gui.__closeButton, GUI.CLASS_DRAG); + dom.unbind(window, 'mousemove', drag); + dom.unbind(window, 'mouseup', dragStop); + + } + + } + + function setWidth(gui, w) { + gui.domElement.style.width = w + 'px'; + // Auto placed save-rows are position fixed, so we have to + // set the width manually if we want it to bleed to the edge + if (gui.__save_row && gui.autoPlace) { + gui.__save_row.style.width = w + 'px'; + }if (gui.__closeButton) { + gui.__closeButton.style.width = w + 'px'; + } + } + + function getCurrentPreset(gui, useInitialValues) { + + var toReturn = {}; + + // For each object I'm remembering + common.each(gui.__rememberedObjects, function(val, index) { + + var saved_values = {}; + + // The controllers I've made for thcommon.isObject by property + var controller_map = + gui.__rememberedObjectIndecesToControllers[index]; + + // Remember each value for each property + common.each(controller_map, function(controller, property) { + saved_values[property] = useInitialValues ? controller.initialValue : controller.getValue(); + }); + + // Save the values for thcommon.isObject + toReturn[index] = saved_values; + + }); + + return toReturn; + + } + + function addPresetOption(gui, name, setSelected) { + var opt = document.createElement('option'); + opt.innerHTML = name; + opt.value = name; + gui.__preset_select.appendChild(opt); + if (setSelected) { + gui.__preset_select.selectedIndex = gui.__preset_select.length - 1; + } + } + + function setPresetSelectIndex(gui) { + for (var index = 0; index < gui.__preset_select.length; index++) { + if (gui.__preset_select[index].value == gui.preset) { + gui.__preset_select.selectedIndex = index; + } + } + } + + function markPresetModified(gui, modified) { + var opt = gui.__preset_select[gui.__preset_select.selectedIndex]; +// console.log('mark', modified, opt); + if (modified) { + opt.innerHTML = opt.value + "*"; + } else { + opt.innerHTML = opt.value; + } + } + + function updateDisplays(controllerArray) { + + + if (controllerArray.length != 0) { + + requestAnimationFrame(function() { + updateDisplays(controllerArray); + }); + + } + + common.each(controllerArray, function(c) { + c.updateDisplay(); + }); + + } + + return GUI; + +})(dat.utils.css, +"
\n\n Here's the new load parameter for your GUI's constructor:\n\n \n\n
\n\n Automatically save\n values to localStorage on exit.\n\n
The values saved to localStorage will\n override those passed to dat.GUI's constructor. This makes it\n easier to work incrementally, but localStorage is fragile,\n and your friends may not see the same values you do.\n \n
\n \n
\n\n
", +".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity 0.1s linear;-o-transition:opacity 0.1s linear;-moz-transition:opacity 0.1s linear;transition:opacity 0.1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1 !important}.dg.main:hover .close-button,.dg.main .close-button.drag{opacity:1}.dg.main .close-button{-webkit-transition:opacity 0.1s linear;-o-transition:opacity 0.1s linear;-moz-transition:opacity 0.1s linear;transition:opacity 0.1s linear;border:0;position:absolute;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-x:hidden}.dg.a.has-save ul{margin-top:27px}.dg.a.has-save ul.closed{margin-top:0}.dg.a .save-row{position:fixed;top:0;z-index:1002}.dg li{-webkit-transition:height 0.1s ease-out;-o-transition:height 0.1s ease-out;-moz-transition:height 0.1s ease-out;transition:height 0.1s ease-out}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;overflow:hidden;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid rgba(0,0,0,0)}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li > *{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:9px}.dg .c select{margin-top:5px}.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{cursor:pointer}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0px 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco, monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px 'Lucida Grande', sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px 4px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid rgba(255,255,255,0.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2fa1d6}.dg .cr.number input[type=text]{color:#2fa1d6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.function:hover,.dg .cr.boolean:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2fa1d6}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}\n", +dat.controllers.factory = (function (OptionController, NumberControllerBox, NumberControllerSlider, StringController, FunctionController, BooleanController, common) { + + return function(object, property) { + + var initialValue = object[property]; + + // Providing options? + if (common.isArray(arguments[2]) || common.isObject(arguments[2])) { + return new OptionController(object, property, arguments[2]); + } + + // Providing a map? + + if (common.isNumber(initialValue)) { + + if (common.isNumber(arguments[2]) && common.isNumber(arguments[3])) { + + // Has min and max. + return new NumberControllerSlider(object, property, arguments[2], arguments[3]); + + } else { + + return new NumberControllerBox(object, property, { min: arguments[2], max: arguments[3] }); + + } + + } + + if (common.isString(initialValue)) { + return new StringController(object, property); + } + + if (common.isFunction(initialValue)) { + return new FunctionController(object, property, ''); + } + + if (common.isBoolean(initialValue)) { + return new BooleanController(object, property); + } + + } + + })(dat.controllers.OptionController, +dat.controllers.NumberControllerBox, +dat.controllers.NumberControllerSlider, +dat.controllers.StringController = (function (Controller, dom, common) { + + /** + * @class Provides a text input to alter the string property of an object. + * + * @extends dat.controllers.Controller + * + * @param {Object} object The object to be manipulated + * @param {string} property The name of the property to be manipulated + * + * @member dat.controllers + */ + var StringController = function(object, property) { + + StringController.superclass.call(this, object, property); + + var _this = this; + + this.__input = document.createElement('input'); + this.__input.setAttribute('type', 'text'); + + dom.bind(this.__input, 'keyup', onChange); + dom.bind(this.__input, 'change', onChange); + dom.bind(this.__input, 'blur', onBlur); + dom.bind(this.__input, 'keydown', function(e) { + if (e.keyCode === 13) { + this.blur(); + } + }); + + + function onChange() { + _this.setValue(_this.__input.value); + } + + function onBlur() { + if (_this.__onFinishChange) { + _this.__onFinishChange.call(_this, _this.getValue()); + } + } + + this.updateDisplay(); + + this.domElement.appendChild(this.__input); + + }; + + StringController.superclass = Controller; + + common.extend( + + StringController.prototype, + Controller.prototype, + + { + + updateDisplay: function() { + // Stops the caret from moving on account of: + // keyup -> setValue -> updateDisplay + if (!dom.isActive(this.__input)) { + this.__input.value = this.getValue(); + } + return StringController.superclass.prototype.updateDisplay.call(this); + } + + } + + ); + + return StringController; + +})(dat.controllers.Controller, +dat.dom.dom, +dat.utils.common), +dat.controllers.FunctionController, +dat.controllers.BooleanController, +dat.utils.common), +dat.controllers.Controller, +dat.controllers.BooleanController, +dat.controllers.FunctionController, +dat.controllers.NumberControllerBox, +dat.controllers.NumberControllerSlider, +dat.controllers.OptionController, +dat.controllers.ColorController = (function (Controller, dom, Color, interpret, common) { + + var ColorController = function(object, property) { + + ColorController.superclass.call(this, object, property); + + this.__color = new Color(this.getValue()); + this.__temp = new Color(0); + + var _this = this; + + this.domElement = document.createElement('div'); + + dom.makeSelectable(this.domElement, false); + + this.__selector = document.createElement('div'); + this.__selector.className = 'selector'; + + this.__saturation_field = document.createElement('div'); + this.__saturation_field.className = 'saturation-field'; + + this.__field_knob = document.createElement('div'); + this.__field_knob.className = 'field-knob'; + this.__field_knob_border = '2px solid '; + + this.__hue_knob = document.createElement('div'); + this.__hue_knob.className = 'hue-knob'; + + this.__hue_field = document.createElement('div'); + this.__hue_field.className = 'hue-field'; + + this.__input = document.createElement('input'); + this.__input.type = 'text'; + this.__input_textShadow = '0 1px 1px '; + + dom.bind(this.__input, 'keydown', function(e) { + if (e.keyCode === 13) { // on enter + onBlur.call(this); + } + }); + + dom.bind(this.__input, 'blur', onBlur); + + dom.bind(this.__selector, 'mousedown', function(e) { + + dom + .addClass(this, 'drag') + .bind(window, 'mouseup', function(e) { + dom.removeClass(_this.__selector, 'drag'); + }); + + }); + + var value_field = document.createElement('div'); + + common.extend(this.__selector.style, { + width: '122px', + height: '102px', + padding: '3px', + backgroundColor: '#222', + boxShadow: '0px 1px 3px rgba(0,0,0,0.3)' + }); + + common.extend(this.__field_knob.style, { + position: 'absolute', + width: '12px', + height: '12px', + border: this.__field_knob_border + (this.__color.v < .5 ? '#fff' : '#000'), + boxShadow: '0px 1px 3px rgba(0,0,0,0.5)', + borderRadius: '12px', + zIndex: 1 + }); + + common.extend(this.__hue_knob.style, { + position: 'absolute', + width: '15px', + height: '2px', + borderRight: '4px solid #fff', + zIndex: 1 + }); + + common.extend(this.__saturation_field.style, { + width: '100px', + height: '100px', + border: '1px solid #555', + marginRight: '3px', + display: 'inline-block', + cursor: 'pointer' + }); + + common.extend(value_field.style, { + width: '100%', + height: '100%', + background: 'none' + }); + + linearGradient(value_field, 'top', 'rgba(0,0,0,0)', '#000'); + + common.extend(this.__hue_field.style, { + width: '15px', + height: '100px', + display: 'inline-block', + border: '1px solid #555', + cursor: 'ns-resize' + }); + + hueGradient(this.__hue_field); + + common.extend(this.__input.style, { + outline: 'none', +// width: '120px', + textAlign: 'center', +// padding: '4px', +// marginBottom: '6px', + color: '#fff', + border: 0, + fontWeight: 'bold', + textShadow: this.__input_textShadow + 'rgba(0,0,0,0.7)' + }); + + dom.bind(this.__saturation_field, 'mousedown', fieldDown); + dom.bind(this.__field_knob, 'mousedown', fieldDown); + + dom.bind(this.__hue_field, 'mousedown', function(e) { + setH(e); + dom.bind(window, 'mousemove', setH); + dom.bind(window, 'mouseup', unbindH); + }); + + function fieldDown(e) { + setSV(e); + // document.body.style.cursor = 'none'; + dom.bind(window, 'mousemove', setSV); + dom.bind(window, 'mouseup', unbindSV); + } + + function unbindSV() { + dom.unbind(window, 'mousemove', setSV); + dom.unbind(window, 'mouseup', unbindSV); + // document.body.style.cursor = 'default'; + } + + function onBlur() { + var i = interpret(this.value); + if (i !== false) { + _this.__color.__state = i; + _this.setValue(_this.__color.toOriginal()); + } else { + this.value = _this.__color.toString(); + } + } + + function unbindH() { + dom.unbind(window, 'mousemove', setH); + dom.unbind(window, 'mouseup', unbindH); + } + + this.__saturation_field.appendChild(value_field); + this.__selector.appendChild(this.__field_knob); + this.__selector.appendChild(this.__saturation_field); + this.__selector.appendChild(this.__hue_field); + this.__hue_field.appendChild(this.__hue_knob); + + this.domElement.appendChild(this.__input); + this.domElement.appendChild(this.__selector); + + this.updateDisplay(); + + function setSV(e) { + + e.preventDefault(); + + var w = dom.getWidth(_this.__saturation_field); + var o = dom.getOffset(_this.__saturation_field); + var s = (e.clientX - o.left + document.body.scrollLeft) / w; + var v = 1 - (e.clientY - o.top + document.body.scrollTop) / w; + + if (v > 1) v = 1; + else if (v < 0) v = 0; + + if (s > 1) s = 1; + else if (s < 0) s = 0; + + _this.__color.v = v; + _this.__color.s = s; + + _this.setValue(_this.__color.toOriginal()); + + + return false; + + } + + function setH(e) { + + e.preventDefault(); + + var s = dom.getHeight(_this.__hue_field); + var o = dom.getOffset(_this.__hue_field); + var h = 1 - (e.clientY - o.top + document.body.scrollTop) / s; + + if (h > 1) h = 1; + else if (h < 0) h = 0; + + _this.__color.h = h * 360; + + _this.setValue(_this.__color.toOriginal()); + + return false; + + } + + }; + + ColorController.superclass = Controller; + + common.extend( + + ColorController.prototype, + Controller.prototype, + + { + + updateDisplay: function() { + + var i = interpret(this.getValue()); + + if (i !== false) { + + var mismatch = false; + + // Check for mismatch on the interpreted value. + + common.each(Color.COMPONENTS, function(component) { + if (!common.isUndefined(i[component]) && + !common.isUndefined(this.__color.__state[component]) && + i[component] !== this.__color.__state[component]) { + mismatch = true; + return {}; // break + } + }, this); + + // If nothing diverges, we keep our previous values + // for statefulness, otherwise we recalculate fresh + if (mismatch) { + common.extend(this.__color.__state, i); + } + + } + + common.extend(this.__temp.__state, this.__color.__state); + + this.__temp.a = 1; + + var flip = (this.__color.v < .5 || this.__color.s > .5) ? 255 : 0; + var _flip = 255 - flip; + + common.extend(this.__field_knob.style, { + marginLeft: 100 * this.__color.s - 7 + 'px', + marginTop: 100 * (1 - this.__color.v) - 7 + 'px', + backgroundColor: this.__temp.toString(), + border: this.__field_knob_border + 'rgb(' + flip + ',' + flip + ',' + flip +')' + }); + + this.__hue_knob.style.marginTop = (1 - this.__color.h / 360) * 100 + 'px' + + this.__temp.s = 1; + this.__temp.v = 1; + + linearGradient(this.__saturation_field, 'left', '#fff', this.__temp.toString()); + + common.extend(this.__input.style, { + backgroundColor: this.__input.value = this.__color.toString(), + color: 'rgb(' + flip + ',' + flip + ',' + flip +')', + textShadow: this.__input_textShadow + 'rgba(' + _flip + ',' + _flip + ',' + _flip +',.7)' + }); + + } + + } + + ); + + var vendors = ['-moz-','-o-','-webkit-','-ms-','']; + + function linearGradient(elem, x, a, b) { + elem.style.background = ''; + common.each(vendors, function(vendor) { + elem.style.cssText += 'background: ' + vendor + 'linear-gradient('+x+', '+a+' 0%, ' + b + ' 100%); '; + }); + } + + function hueGradient(elem) { + elem.style.background = ''; + elem.style.cssText += 'background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);' + elem.style.cssText += 'background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);' + elem.style.cssText += 'background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);' + elem.style.cssText += 'background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);' + elem.style.cssText += 'background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);' + } + + + return ColorController; + +})(dat.controllers.Controller, +dat.dom.dom, +dat.color.Color = (function (interpret, math, toString, common) { + + var Color = function() { + + this.__state = interpret.apply(this, arguments); + + if (this.__state === false) { + throw 'Failed to interpret color arguments'; + } + + this.__state.a = this.__state.a || 1; + + + }; + + Color.COMPONENTS = ['r','g','b','h','s','v','hex','a']; + + common.extend(Color.prototype, { + + toString: function() { + return toString(this); + }, + + toOriginal: function() { + return this.__state.conversion.write(this); + } + + }); + + defineRGBComponent(Color.prototype, 'r', 2); + defineRGBComponent(Color.prototype, 'g', 1); + defineRGBComponent(Color.prototype, 'b', 0); + + defineHSVComponent(Color.prototype, 'h'); + defineHSVComponent(Color.prototype, 's'); + defineHSVComponent(Color.prototype, 'v'); + + Object.defineProperty(Color.prototype, 'a', { + + get: function() { + return this.__state.a; + }, + + set: function(v) { + this.__state.a = v; + } + + }); + + Object.defineProperty(Color.prototype, 'hex', { + + get: function() { + + if (!this.__state.space !== 'HEX') { + this.__state.hex = math.rgb_to_hex(this.r, this.g, this.b); + } + + return this.__state.hex; + + }, + + set: function(v) { + + this.__state.space = 'HEX'; + this.__state.hex = v; + + } + + }); + + function defineRGBComponent(target, component, componentHexIndex) { + + Object.defineProperty(target, component, { + + get: function() { + + if (this.__state.space === 'RGB') { + return this.__state[component]; + } + + recalculateRGB(this, component, componentHexIndex); + + return this.__state[component]; + + }, + + set: function(v) { + + if (this.__state.space !== 'RGB') { + recalculateRGB(this, component, componentHexIndex); + this.__state.space = 'RGB'; + } + + this.__state[component] = v; + + } + + }); + + } + + function defineHSVComponent(target, component) { + + Object.defineProperty(target, component, { + + get: function() { + + if (this.__state.space === 'HSV') + return this.__state[component]; + + recalculateHSV(this); + + return this.__state[component]; + + }, + + set: function(v) { + + if (this.__state.space !== 'HSV') { + recalculateHSV(this); + this.__state.space = 'HSV'; + } + + this.__state[component] = v; + + } + + }); + + } + + function recalculateRGB(color, component, componentHexIndex) { + + if (color.__state.space === 'HEX') { + + color.__state[component] = math.component_from_hex(color.__state.hex, componentHexIndex); + + } else if (color.__state.space === 'HSV') { + + common.extend(color.__state, math.hsv_to_rgb(color.__state.h, color.__state.s, color.__state.v)); + + } else { + + throw 'Corrupted color state'; + + } + + } + + function recalculateHSV(color) { + + var result = math.rgb_to_hsv(color.r, color.g, color.b); + + common.extend(color.__state, + { + s: result.s, + v: result.v + } + ); + + if (!common.isNaN(result.h)) { + color.__state.h = result.h; + } else if (common.isUndefined(color.__state.h)) { + color.__state.h = 0; + } + + } + + return Color; + +})(dat.color.interpret, +dat.color.math = (function () { + + var tmpComponent; + + return { + + hsv_to_rgb: function(h, s, v) { + + var hi = Math.floor(h / 60) % 6; + + var f = h / 60 - Math.floor(h / 60); + var p = v * (1.0 - s); + var q = v * (1.0 - (f * s)); + var t = v * (1.0 - ((1.0 - f) * s)); + var c = [ + [v, t, p], + [q, v, p], + [p, v, t], + [p, q, v], + [t, p, v], + [v, p, q] + ][hi]; + + return { + r: c[0] * 255, + g: c[1] * 255, + b: c[2] * 255 + }; + + }, + + rgb_to_hsv: function(r, g, b) { + + var min = Math.min(r, g, b), + max = Math.max(r, g, b), + delta = max - min, + h, s; + + if (max != 0) { + s = delta / max; + } else { + return { + h: NaN, + s: 0, + v: 0 + }; + } + + if (r == max) { + h = (g - b) / delta; + } else if (g == max) { + h = 2 + (b - r) / delta; + } else { + h = 4 + (r - g) / delta; + } + h /= 6; + if (h < 0) { + h += 1; + } + + return { + h: h * 360, + s: s, + v: max / 255 + }; + }, + + rgb_to_hex: function(r, g, b) { + var hex = this.hex_with_component(0, 2, r); + hex = this.hex_with_component(hex, 1, g); + hex = this.hex_with_component(hex, 0, b); + return hex; + }, + + component_from_hex: function(hex, componentIndex) { + return (hex >> (componentIndex * 8)) & 0xFF; + }, + + hex_with_component: function(hex, componentIndex, value) { + return value << (tmpComponent = componentIndex * 8) | (hex & ~ (0xFF << tmpComponent)); + } + + } + +})(), +dat.color.toString, +dat.utils.common), +dat.color.interpret, +dat.utils.common), +dat.utils.requestAnimationFrame = (function () { + + /** + * requirejs version of Paul Irish's RequestAnimationFrame + * http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + */ + + return window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function(callback, element) { + + window.setTimeout(callback, 1000 / 60); + + }; +})(), +dat.dom.CenteredDiv = (function (dom, common) { + + + var CenteredDiv = function() { + + this.backgroundElement = document.createElement('div'); + common.extend(this.backgroundElement.style, { + backgroundColor: 'rgba(0,0,0,0.8)', + top: 0, + left: 0, + display: 'none', + zIndex: '1000', + opacity: 0, + WebkitTransition: 'opacity 0.2s linear' + }); + + dom.makeFullscreen(this.backgroundElement); + this.backgroundElement.style.position = 'fixed'; + + this.domElement = document.createElement('div'); + common.extend(this.domElement.style, { + position: 'fixed', + display: 'none', + zIndex: '1001', + opacity: 0, + WebkitTransition: '-webkit-transform 0.2s ease-out, opacity 0.2s linear' + }); + + + document.body.appendChild(this.backgroundElement); + document.body.appendChild(this.domElement); + + var _this = this; + dom.bind(this.backgroundElement, 'click', function() { + _this.hide(); + }); + + + }; + + CenteredDiv.prototype.show = function() { + + var _this = this; + + + + this.backgroundElement.style.display = 'block'; + + this.domElement.style.display = 'block'; + this.domElement.style.opacity = 0; +// this.domElement.style.top = '52%'; + this.domElement.style.webkitTransform = 'scale(1.1)'; + + this.layout(); + + common.defer(function() { + _this.backgroundElement.style.opacity = 1; + _this.domElement.style.opacity = 1; + _this.domElement.style.webkitTransform = 'scale(1)'; + }); + + }; + + CenteredDiv.prototype.hide = function() { + + var _this = this; + + var hide = function() { + + _this.domElement.style.display = 'none'; + _this.backgroundElement.style.display = 'none'; + + dom.unbind(_this.domElement, 'webkitTransitionEnd', hide); + dom.unbind(_this.domElement, 'transitionend', hide); + dom.unbind(_this.domElement, 'oTransitionEnd', hide); + + }; + + dom.bind(this.domElement, 'webkitTransitionEnd', hide); + dom.bind(this.domElement, 'transitionend', hide); + dom.bind(this.domElement, 'oTransitionEnd', hide); + + this.backgroundElement.style.opacity = 0; +// this.domElement.style.top = '48%'; + this.domElement.style.opacity = 0; + this.domElement.style.webkitTransform = 'scale(1.1)'; + + }; + + CenteredDiv.prototype.layout = function() { + this.domElement.style.left = window.innerWidth/2 - dom.getWidth(this.domElement) / 2 + 'px'; + this.domElement.style.top = window.innerHeight/2 - dom.getHeight(this.domElement) / 2 + 'px'; + }; + + function lockScroll(e) { + console.log(e); + } + + return CenteredDiv; + +})(dat.dom.dom, +dat.utils.common), +dat.dom.dom, +dat.utils.common); + +/***/ }), +/* 25 */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports = __webpack_require__.p + "./assets/iridescent-ec82e7.bmp"; + +/***/ }), +/* 26 */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports = __webpack_require__.p + "./assets/wahoo-1bfe66.bmp"; + +/***/ }), +/* 27 */ +/***/ (function(module, exports) { + +/** + * @author alteredq / http://alteredqualia.com/ + * + * Full-screen textured quad shader + */ + +module.exports = { + 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 texel = texture2D( tDiffuse, vUv );", + "gl_FragColor = opacity * texel;", + + "}" + ].join("\n") +}; + + +/***/ }), +/* 28 */ +/***/ (function(module, exports) { + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +module.exports = function(THREE) { + function ClearMaskPass() { + if (!(this instanceof ClearMaskPass)) return new ClearMaskPass(scene, camera); + this.enabled = true; + }; + + ClearMaskPass.prototype = { + render: function ( renderer, writeBuffer, readBuffer, delta ) { + var context = renderer.context; + context.disable( context.STENCIL_TEST ); + } + }; + + return ClearMaskPass +}; + +/***/ }), +/* 29 */ +/***/ (function(module, exports) { + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +module.exports = function(THREE) { + function MaskPass( scene, camera ) { + if (!(this instanceof MaskPass)) return new MaskPass(scene, camera); + + this.scene = scene; + this.camera = camera; + + this.enabled = true; + this.clear = true; + this.needsSwap = false; + + this.inverse = false; + }; + + MaskPass.prototype = { + + render: function ( renderer, writeBuffer, readBuffer, delta ) { + + var context = renderer.context; + + // don't update color or depth + + context.colorMask( false, false, false, false ); + context.depthMask( false ); + + // set up stencil + + var writeValue, clearValue; + + if ( this.inverse ) { + + writeValue = 0; + clearValue = 1; + + } else { + + writeValue = 1; + clearValue = 0; + + } + + context.enable( context.STENCIL_TEST ); + context.stencilOp( context.REPLACE, context.REPLACE, context.REPLACE ); + context.stencilFunc( context.ALWAYS, writeValue, 0xffffffff ); + context.clearStencil( clearValue ); + + // draw into the stencil buffer + + renderer.render( this.scene, this.camera, readBuffer, this.clear ); + renderer.render( this.scene, this.camera, writeBuffer, this.clear ); + + // re-enable update of color and depth + + context.colorMask( true, true, true, true ); + context.depthMask( true ); + + // only render where stencil is set to 1 + + context.stencilFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1 + context.stencilOp( context.KEEP, context.KEEP, context.KEEP ); + + } + + }; + + return MaskPass +}; + + +/***/ }), +/* 30 */ +/***/ (function(module, exports) { + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +module.exports = function(THREE) { + function RenderPass( scene, camera, overrideMaterial, clearColor, clearAlpha ) { + if (!(this instanceof RenderPass)) return new RenderPass(scene, camera, overrideMaterial, clearColor, clearAlpha); + + this.scene = scene; + this.camera = camera; + + this.overrideMaterial = overrideMaterial; + + this.clearColor = clearColor; + this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 1; + + this.oldClearColor = new THREE.Color(); + this.oldClearAlpha = 1; + + this.enabled = true; + this.clear = true; + this.needsSwap = false; + + }; + + RenderPass.prototype = { + + render: function ( renderer, writeBuffer, readBuffer, delta ) { + + this.scene.overrideMaterial = this.overrideMaterial; + + if ( this.clearColor ) { + + this.oldClearColor.copy( renderer.getClearColor() ); + this.oldClearAlpha = renderer.getClearAlpha(); + + renderer.setClearColor( this.clearColor, this.clearAlpha ); + + } + + renderer.render( this.scene, this.camera, readBuffer, this.clear ); + + if ( this.clearColor ) { + + renderer.setClearColor( this.oldClearColor, this.oldClearAlpha ); + + } + + this.scene.overrideMaterial = null; + + } + + }; + + return RenderPass; + +}; + + +/***/ }), +/* 31 */ +/***/ (function(module, exports) { + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +module.exports = function(THREE, EffectComposer) { + function ShaderPass( shader, textureID ) { + if (!(this instanceof ShaderPass)) return new ShaderPass(shader, textureID); + + this.textureID = ( textureID !== undefined ) ? textureID : "tDiffuse"; + + this.uniforms = THREE.UniformsUtils.clone( shader.uniforms ); + + this.material = new THREE.ShaderMaterial( { + + uniforms: this.uniforms, + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader + + } ); + + this.renderToScreen = false; + + this.enabled = true; + this.needsSwap = true; + this.clear = false; + + }; + + ShaderPass.prototype = { + + render: function ( renderer, writeBuffer, readBuffer, delta ) { + + if ( this.uniforms[ this.textureID ] ) { + + this.uniforms[ this.textureID ].value = readBuffer; + + } + + EffectComposer.quad.material = this.material; + + if ( this.renderToScreen ) { + + renderer.render( EffectComposer.scene, EffectComposer.camera ); + + } else { + + renderer.render( EffectComposer.scene, EffectComposer.camera, writeBuffer, this.clear ); + + } + + } + + }; + + return ShaderPass; + +}; + +/***/ }), +/* 32 */ +/***/ (function(module, exports) { + +module.exports = "uniform sampler2D tDiffuse;\nuniform float u_amount;\nuniform float sWidth;\nuniform float sHeight;\nvarying vec2 f_uv;\n\n\n// Get the pixel in uv coordinates using an offset from the current position\nvec2 getPixel(float x, float y) {\n\treturn f_uv + vec2(1.0/sWidth, 1.0/sHeight) * vec2(x, y);\n}\n\n// Retrieves the color from the texture\nvec4 getColor(vec2 pixel) {\n\tvec4 col = texture2D(tDiffuse, pixel);\n\treturn col;\n}\n\nvoid main() {\n\t// Get colors for each pixel\n\tvec4 a = getColor(getPixel(-1.0, -1.0));\n\tvec4 b = getColor(getPixel(0.0, -1.0));\n\tvec4 c = getColor(getPixel(1.0, -1.0));\n\tvec4 d = getColor(getPixel(-1.0, 0.0));\n\tvec4 e = getColor(getPixel(0.0, 0.0));\n\tvec4 f = getColor(getPixel(1.0, 0.0));\n\tvec4 g = getColor(getPixel(-1.0, 1.0));\n\tvec4 h = getColor(getPixel(0.0, 1.0));\n\tvec4 i = getColor(getPixel(1.0, 1.0));\n\n\t// Apply weighted average\n\tgl_FragColor = 0.1107* (a + c + g + i) + 0.1113* (b + d + h + f) + 0.1119 * e;\n} " + +/***/ }), +/* 33 */ +/***/ (function(module, exports) { + +module.exports = "\nuniform sampler2D tDiffuse;\nuniform float u_amount;\nvarying vec2 f_uv;\n\n// tDiffuse is a special uniform sampler that THREE.js will bind the previously rendered frame to\n\nvoid main() {\n vec4 col = texture2D(tDiffuse, f_uv);\n float gray = dot(col.rgb, vec3(0.299, 0.587, 0.114));\n\n col.rgb = vec3(gray, gray, gray) * (u_amount) + col.rgb * (1.0 - u_amount);\n\n gl_FragColor = col;\n} " + +/***/ }), +/* 34 */ +/***/ (function(module, exports) { + +module.exports = "\nuniform sampler2D tDiffuse;\nuniform float u_amount;\nvarying vec2 f_uv;\n\n// tDiffuse is a special uniform sampler that THREE.js will bind the previously rendered frame to\nvoid main() {\n vec4 col = texture2D(tDiffuse, f_uv);\n col = vec4(1.0 - col.x, 1.0 - col.y, 1.0 - col.z, 1.0 - u_amount);\n gl_FragColor = col;\n} " + +/***/ }), +/* 35 */ +/***/ (function(module, exports) { + +module.exports = "\nuniform sampler2D texture;\nuniform int u_useTexture;\nuniform vec3 u_albedo;\nuniform vec3 u_ambient;\nuniform vec3 u_lightPos;\nuniform vec3 u_lightCol;\nuniform float u_lightIntensity;\nuniform vec3 u_camPos;\n\nvarying vec3 f_position;\nvarying vec3 f_normal;\nvarying vec2 f_uv;\nvarying float noise;\n\n\nvoid main() {\n vec4 color = vec4(u_albedo, 1.0);\n float d = clamp(dot(f_normal, normalize(u_camPos - f_position)), 0.0, 1.0);\n\n // Read from texture using relation to the view vector and a little bit of noise\n if (u_useTexture == 1) {\n color = texture2D(texture, vec2(f_uv.x - d*float(noise), f_uv.y - d*float(noise)));\n }\n\n gl_FragColor = vec4(d * color.rgb * u_lightCol * u_lightIntensity + u_ambient, 1.0);\n}" + +/***/ }), +/* 36 */ +/***/ (function(module, exports) { + +module.exports = "\nvarying vec2 f_uv;\nvarying vec3 f_normal;\nvarying vec3 f_position;\nvarying float noise;\n\nfloat random(float a, float b, float c) {\n return fract(sin(dot(vec3(a, b, c), vec3(12.9898, 78.233, 78.233)))*43758.5453);\n}\n\nfloat lerp(float a, float b, float t) {\n return a * (1.0 - t) + b * t;\n}\n\nvec4 lerp(vec4 a, vec4 b, float t) {\n return a * (1.0 - t) + b * t;\n}\n\nfloat cerp(float a, float b, float t) {\n float cos_t = (1.0 - cos(t*3.14159)) * 0.5;\n return lerp(a, b, cos_t);\n}\n\nfloat interpolateNoise(float x, float y, float z) {\n float x0, y0, z0, x1, y1, z1;\n \n // Find the grid voxel that this point falls in\n x0 = floor(x);\n y0 = floor(y);\n z0 = floor(z);\n \n x1 = x0 + 1.0;\n y1 = y0 + 1.0;\n z1 = z0 + 1.0;\n \n // Generate noise at each of the 8 points\n float FUL, FUR, FLL, FLR, BUL, BUR, BLL, BLR;\n \n // front upper left\n FUL = random(x0, y1, z1);\n \n // front upper right\n FUR = random(x1, y1, z1);\n \n // front lower left\n FLL = random(x0, y0, z1);\n \n // front lower right\n FLR = random(x1, y0, z1);\n \n // back upper left\n BUL = random(x0, y1, z0);\n \n // back upper right\n BUR = random(x1, y1, z0);\n \n // back lower left\n BLL = random(x0, y0, z0);\n \n // back lower right\n BLR = random(x1, y0, z0);\n \n // Find the interpolate t values\n float n0, n1, m0, m1, v;\n float tx = fract(x - x0);\n float ty = fract(y - y0);\n float tz = fract(z - z0);\n tx = (x - x0);\n ty = (y - y0);\n tz = (z - z0);\n \n // interpolate along x and y for back\n n0 = cerp(BLL, BLR, tx);\n n1 = cerp(BUL, BUR, tx);\n m0 = cerp(n0, n1, ty);\n \n // interpolate along x and y for front\n n0 = cerp(FLL, FLR, tx);\n n1 = cerp(FUL, FUR, tx);\n m1 = cerp(n0, n1, ty);\n \n // interpolate along z\n v = cerp(m0, m1, tz);\n \n return v;\n}\n\nfloat generateNoise(float x, float y, float z) {\n float total = 0.0;\n float persistence = 1.0 / 2.0;\n int its = 0;\n for (int i = 0; i < 32; i++) {\n float freq = pow(2.0, float(i));\n float ampl = pow(persistence, float(i));\n total += interpolateNoise(freq*x, freq*y, freq*z)*ampl;\n }\n return total;\n}\n\nvoid main() {\n // Pass noise to the fragment shader\n\tnoise = generateNoise(position.x, position.y, position.z);\n f_uv = uv;\n f_normal = normal;\n f_position = position;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}" + +/***/ }), +/* 37 */ +/***/ (function(module, exports) { + +module.exports = "\nuniform sampler2D texture;\nuniform int u_useTexture;\nuniform vec3 u_albedo;\nuniform vec3 u_ambient;\nuniform vec3 u_lightPos;\nuniform vec3 u_lightCol;\nuniform float u_lightIntensity;\n\nvarying vec3 f_position;\nvarying vec3 f_normal;\nvarying vec2 f_uv;\n\nvoid main() {\n vec4 color = vec4(u_albedo, 1.0);\n \n if (u_useTexture == 1) {\n color = texture2D(texture, f_uv);\n }\n\n float d = clamp(dot(f_normal, normalize(u_lightPos - f_position)), 0.0, 1.0);\n\n gl_FragColor = vec4(d * color.rgb * u_lightCol * u_lightIntensity + u_ambient, 1.0);\n}" + +/***/ }), +/* 38 */ +/***/ (function(module, exports) { + +module.exports = "\nvarying vec2 f_uv;\nvarying vec3 f_normal;\nvarying vec3 f_position;\n\n// uv, position, projectionMatrix, modelViewMatrix, normal\nvoid main() {\n f_uv = uv;\n f_normal = normal;\n f_position = position;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}" + +/***/ }), +/* 39 */ +/***/ (function(module, exports) { + +module.exports = "uniform sampler2D tDiffuse;\nuniform float u_amount;\nvarying vec2 f_uv;\n\n// tDiffuse is a special uniform sampler that THREE.js will bind the previously rendered frame to\nfloat random(float a, float b, float c) {\n return fract(sin(dot(vec3(a, b, c), vec3(12.9898, 78.233, 78.233)))*43758.5453);\n}\n\nvoid main() {\n // Retrieve color and transform to gray scale\n vec4 col = texture2D(tDiffuse, f_uv);\n float gray = dot(col.rgb, vec3(0.299, 0.587, 0.114));\n col.rgb = vec3(gray, gray, gray) * (u_amount) + col.rgb * (1.0 - u_amount);\n\n // Scale probability with of darkness\n float prob = random(f_uv.x, f_uv.y, 1.0)*(1.0 - col.r*col.b*col.g) / 4.0; \n\n // Compare probability to darkness and shade black if dark enough, white otherwise\n if (prob > col.r*col.b*col.g) {\n \tgl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); \n }\n else {\n \tgl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n }\n \n} " + +/***/ }), +/* 40 */ +/***/ (function(module, exports) { + +module.exports = "\nuniform sampler2D tDiffuse;\nuniform float u_amount;\nuniform float sWidth;\nuniform float sHeight;\nvarying vec2 f_uv;\n\n\nvec2 getPixel(float x, float y) {\n\treturn f_uv + vec2(1.0/sWidth, 1.0/sHeight) * vec2(x, y);\n}\n\nvec4 getGreyscaleColor(vec2 pixel) {\n\tvec4 col = texture2D(tDiffuse, pixel);\n\tfloat gray = dot(col.rgb, vec3(0.299, 0.587, 0.114));\n\tcol.rgb = vec3(gray, gray, gray) * (u_amount) + col.rgb * (1.0 - u_amount);\n\treturn col;\n}\n\nvoid main() {\n\t// Gets greyscale pixel from neighboring pixels\n\tvec4 a = getGreyscaleColor(getPixel(-1.0, -1.0));\n\tvec4 b = getGreyscaleColor(getPixel(0.0, -1.0));\n\tvec4 c = getGreyscaleColor(getPixel(1.0, -1.0));\n\tvec4 d = getGreyscaleColor(getPixel(-1.0, 0.0));\n\tvec4 e = getGreyscaleColor(getPixel(0.0, 0.0));\n\tvec4 f = getGreyscaleColor(getPixel(1.0, 0.0));\n\tvec4 g = getGreyscaleColor(getPixel(-1.0, 1.0));\n\tvec4 h = getGreyscaleColor(getPixel(0.0, 1.0));\n\tvec4 i = getGreyscaleColor(getPixel(1.0, 1.0));\n\n\tfloat r = sqrt(pow(-a.r - 2.0*d.r - g.r + c.r + 2.0*f.r + i.r, 2.0) \n\t\t+ pow(a.r + 2.0*b.r + c.r - g.r -2.0*h.r - i.r, 2.0));\n\tfloat gc = sqrt(pow(-a.g - 2.0*d.g - g.g + c.g + 2.0*f.g + i.g, 2.0) \n\t\t+ pow(a.g + 2.0*b.g + c.g - g.g -2.0*h.g - i.g, 2.0));\n\tfloat bc = sqrt(pow(-a.b - 2.0*d.b - g.b + c.b + 2.0*f.b + i.b, 2.0) \n\t\t+ pow(a.b + 2.0*b.b + c.b - g.b -2.0*h.b - i.b, 2.0));\n gl_FragColor = vec4(r, gc, bc, 1.0);\n} " + +/***/ }), +/* 41 */ +/***/ (function(module, exports) { + +module.exports = "\nuniform sampler2D texture;\nuniform int u_useTexture;\nuniform vec3 u_albedo;\nuniform vec3 u_ambient;\nuniform vec3 u_lightPos;\nuniform vec3 u_lightCol;\nuniform float u_lightIntensity;\nuniform vec3 u_camPos;\nuniform vec3 u_camDir;\nvarying vec3 f_position;\nvarying vec3 f_normal;\nvarying vec2 f_uv;\n\nvoid main() {\n vec4 color = vec4(u_albedo, 1.0);\n \n if (u_useTexture == 1) {\n color = texture2D(texture, f_uv);\n }\n\n float d = clamp(dot(f_normal, normalize(u_lightPos - f_position)), 0.0, 1.0);\n vec3 finalColor = d * color.rgb * u_lightCol * u_lightIntensity + u_ambient;\n \tfinalColor.x = floor(finalColor.x*3.0)/3.0;\n \tfinalColor.y = floor(finalColor.y*3.0)/3.0;\n \tfinalColor.z = floor(finalColor.z*3.0)/3.0;\n \tvec3 view_vec = -normalize(u_camPos - f_position);\n \tif (abs(dot(f_normal, view_vec)) <= 0.4) {\n \t\tfinalColor = vec3(0.0, 0.0, 0.0);\n \t}\n gl_FragColor = vec4(finalColor, 1.0);\n}" + +/***/ }), +/* 42 */ +/***/ (function(module, exports) { + +module.exports = "\nvarying vec2 f_uv;\nvarying vec3 f_normal;\nvarying vec3 f_position;\n\n// uv, position, projectionMatrix, modelViewMatrix, normal\nvoid main() {\n f_uv = uv;\n f_normal = normal;\n f_position = position;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}" + +/***/ }), +/* 43 */ +/***/ (function(module, exports) { + +module.exports = "\nuniform sampler2D tDiffuse;\nuniform float u_amount;\nuniform float sWidth;\nuniform float sHeight;\nuniform vec3 u_color;\nvarying vec2 f_uv;\n\n\nvec2 getPixel(float x, float y) {\n\treturn f_uv + vec2(1.0/sWidth, 1.0/sHeight) * vec2(x, y);\n}\nfloat getDistance(vec2 pixel) {\n\treturn sqrt(pow(pixel.x - 0.5, 2.0) + pow(pixel.y - 0.5, 2.0));\n}\nvec4 getColor() {\n\tvec4 col = texture2D(tDiffuse, f_uv);\n\treturn col;\n}\nvec4 lerp(vec4 c1, vec4 c2, float t) {\n\treturn (1.0 - t)*c1 + t*c2;\n}\n// tDiffuse is a special uniform sampler that THREE.js will bind the previously rendered frame to\nvoid main() {\n gl_FragColor = lerp(getColor(), u_amount*vec4(u_color, 1), clamp(getDistance(getPixel(0.0, 0.0)), 0.0, 1.0));\n\n} " + +/***/ }), +/* 44 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _statsJs = __webpack_require__(8); + +var _statsJs2 = _interopRequireDefault(_statsJs); + +var _mario = __webpack_require__(3); + +var _setup = __webpack_require__(6); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +__webpack_require__(7); + +var THREE = __webpack_require__(0); +var OrbitControls = __webpack_require__(9)(THREE); + +window.addEventListener('load', function () { + var stats = new _statsJs2.default(); + stats.setMode(1); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.left = '0px'; + stats.domElement.style.top = '0px'; + document.body.appendChild(stats.domElement); + + var scene = new THREE.Scene(); + var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); + var renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.setClearColor(0x999999, 1.0); + + var controls = new OrbitControls(camera, renderer.domElement); + controls.enableDamping = true; + controls.enableZoom = true; + controls.rotateSpeed = 0.3; + controls.zoomSpeed = 1.0; + controls.panSpeed = 2.0; + + document.body.appendChild(renderer.domElement); + + window.addEventListener('resize', function () { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + renderer.setSize(window.innerWidth, window.innerHeight); + }); + + var mesh, shader, post; + // this gets called when we set the shader + function shaderSet(Shader, gui) { + // create the shader and initialize its gui + shader = new Shader(renderer, scene, camera); + shader.initGUI(gui); + + // recreate the mesh with a new material + if (mesh) scene.remove(mesh); + _mario.objLoaded.then(function (geo) { + mesh = new THREE.Mesh(geo, shader.material); + scene.add(mesh); + }); + } + + // this gets called when we set the postprocess shader + function postProcessSet(Post, gui) { + // create the shader and initialize its gui + post = new Post(renderer, scene, camera); + post.initGUI(gui); + } + + (0, _setup.setupGUI)(shaderSet, postProcessSet); + + _mario.objLoaded.then(function (geo) { + // point the camera to Mario on load + camera.position.set(5, 10, 15); + var center = geo.boundingSphere.center; + camera.lookAt(center); + controls.target.set(center.x, center.y, center.z); + }); + + (function tick() { + controls.update(); + stats.begin(); + if (shader && shader.update) shader.update(); // perform any necessary updates + if (post && post.update) post.update(); // perform any necessary updates + if (post) post.render(); // render the scene + stats.end(); + requestAnimationFrame(tick); + })(); +}); + +/***/ }) +/******/ ]); +//# sourceMappingURL=bundle.js.map \ No newline at end of file diff --git a/build/bundle.js.map b/build/bundle.js.map new file mode 100644 index 0000000..780fe27 --- /dev/null +++ b/build/bundle.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///webpack/bootstrap c0ef4666137c2c569142","webpack:///./~/three/build/three.module.js","webpack:///./~/three-effectcomposer/index.js","webpack:///./src/glsl/pass-vert.glsl","webpack:///./src/mario.js","webpack:///./src/assets/wahoo.obj","webpack:///./~/three-obj-loader/dist/index.js","webpack:///./src/setup.js","webpack:///./index.html","webpack:///./~/stats-js/build/stats.min.js","webpack:///./~/three-orbit-controls/index.js","webpack:///./src/iridescentmario.js","webpack:///./src/post/gaussian.js","webpack:///./src/post/grayscale.js","webpack:///./src/post/index.js","webpack:///./src/post/invert.js","webpack:///./src/post/pointilism.js","webpack:///./src/post/sobel.js","webpack:///./src/post/vignette.js","webpack:///./src/shaders/index.js","webpack:///./src/shaders/iridescent.js","webpack:///./src/shaders/lambert.js","webpack:///./src/shaders/toon.js","webpack:///./~/dat-gui/index.js","webpack:///./~/dat-gui/vendor/dat.color.js","webpack:///./~/dat-gui/vendor/dat.gui.js","webpack:///./src/assets/iridescent.bmp","webpack:///./src/assets/wahoo.bmp","webpack:///./~/three-copyshader/index.js","webpack:///./~/three-effectcomposer/lib/clearmaskpass.js","webpack:///./~/three-effectcomposer/lib/maskpass.js","webpack:///./~/three-effectcomposer/lib/renderpass.js","webpack:///./~/three-effectcomposer/lib/shaderpass.js","webpack:///./src/glsl/gaussian-frag.glsl","webpack:///./src/glsl/grayscale-frag.glsl","webpack:///./src/glsl/invert-frag.glsl","webpack:///./src/glsl/iridescent-frag.glsl","webpack:///./src/glsl/iridescent-vert.glsl","webpack:///./src/glsl/lambert-frag.glsl","webpack:///./src/glsl/lambert-vert.glsl","webpack:///./src/glsl/pointilism-frag.glsl","webpack:///./src/glsl/sobel-frag.glsl","webpack:///./src/glsl/toon-frag.glsl","webpack:///./src/glsl/toon-vert.glsl","webpack:///./src/glsl/vignette-frag.glsl","webpack:///./src/main.js"],"names":["THREE","require","textureLoaded","Promise","resolve","reject","TextureLoader","load","texture","objLoaded","OBJLoader","obj","geo","children","geometry","computeBoundingSphere","setupGUI","Shaders","Post","GUI","prototype","removeFolder","name","folder","__folders","close","__ul","removeChild","domElement","parentNode","onResize","emptyFolder","i","__controllers","length","remove","shaderSet","postProcessSet","gui","opts","shader","post","shaderControl","add","Object","keys","onChange","setShader","shaderFolder","addFolder","open","postControl","setPostProcess","postFolder","updateDisplay","Gaussian","EffectComposer","options","amount","GaussianShader","ShaderPass","uniforms","tDiffuse","type","value","u_amount","sHeight","screen","height","sWidth","width","vertexShader","fragmentShader","renderer","scene","camera","composer","addPass","RenderPass","renderToScreen","initGUI","val","material","render","Grayscale","GrayscaleShader","None","default","invert","t","Date","invertShader","time","getTime","Pointilism","PointilismShader","SobelShader","Vignette","color","VignetteShaders","u_color","Color","lightColor","addColor","Shader","u_lightCol","u_lightIntensity","u_albedo","u_ambient","u_useTexture","ShaderMaterial","useTexture","albedo","ambient","u_lightPos","Vector3","lightIntensity","u_camPos","position","then","pLocal","pWorld","applyMatrix4","matrixWorld","dir","sub","normalize","u_camDir","OrbitControls","window","addEventListener","stats","setMode","style","left","top","document","body","appendChild","Scene","PerspectiveCamera","innerWidth","innerHeight","WebGLRenderer","antialias","setPixelRatio","devicePixelRatio","setSize","setClearColor","controls","enableDamping","enableZoom","rotateSpeed","zoomSpeed","panSpeed","aspect","updateProjectionMatrix","mesh","Mesh","set","center","boundingSphere","lookAt","target","x","y","z","tick","update","begin","end","requestAnimationFrame"],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA,mDAA2C,cAAc;;AAEzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChEA;AAAA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,uBAAuB,0BAA0B;;AAEjD;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA,eAAe,YAAY;;AAE3B;;AAEA;;AAEA,eAAe,YAAY;;AAE3B;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA,mBAAmB,QAAQ;;AAE3B;;AAEA;;AAEA,KAAK;;AAEL;;AAEA,KAAK;;AAEL;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,0BAA0B;AAC1B,0BAA0B;AAC1B;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA,GAAG;;AAEH;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,qCAAqC,sBAAsB;;AAE3D;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,0BAA0B;;;AAG1B;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA,EAAE;;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AEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA,uBAAuB,kBAAkB;;AAEzC;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA,yBAAyB;AACzB;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA,GAAG;;AAEH;;AAEA;AACA;AACA;AACA;;AAEA,GAAG;;AAEH;;AAEA;AACA;AACA;AACA;;AAEA,GAAG;;AAEH;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,KAAK;;AAEL;;AAEA;;AAEA,IAAI;;AAEJ;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA,GAAG;;AAEH;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA,GAAG;;AAEH;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,0BAA0B;AAC1B,0BAA0B;AAC1B,0BAA0B;AAC1B;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;AACA;;AAEA,GAAG;;AAEH;AACA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,EAA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,sBAAsB,0MAA0M,wKAAwK,mCAAmC,yKAAyK;;AAE1nB,yCAAyC,yKAAyK,8EAA8E,GAAG;;AAEnS,kEAAkE,wHAAwH;;AAE1L;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,GAAG;;AAEH;;AAEA,GAAG;;AAEH;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,IAAI;;AAEJ;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;;AAGA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;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;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA,6CAA6C;;AAE7C;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,kBAAkB,OAAO;;AAEzB;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAE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;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA,IAAI;;AAEJ;AACA;;AAEA,IAAI;;AAEJ;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA,IAAI;;AAEJ;AACA;;AAEA;;AAEA,GAAG;;AAEH;;AAEA;;AAEA;AACA;;AAEA,IAAI;;AAEJ;AACA;;AAEA;;AAEA,GAAG;;AAEH;;AAEA;;AAEA;AACA;;AAEA,IAAI;;AAEJ;AACA;;AAEA;;AAEA,GAAG;;AAEH;;AAEA;;AAEA;AACA;;AAEA,IAAI;;AAEJ;AACA;;AAEA;;AAEA,GAAG;;AAEH;;AAEA;;AAEA;AACA;;AAEA,IAAI;;AAEJ;AACA;;AAEA;;AAEA,GAAG;;AAEH;;AAEA;;AAEA;AACA;;AAEA,IAAI;;AAE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AEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,GAAG;;AAEH;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA,4CAA4C,OAAO;;AAEnD;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;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AEA;AACA;;AAEA,qBAAqB;AACrB,qBAAqB;;AAErB;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,6DAA6D;;AAE7D;AACA;;AAEA;;AAEA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA,EAAE;;AAEF;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,gEAAgE;;AAEhE;AACA;;AAEA;;AAEA;;AAEA,CAAC;;AAED;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,6DAA6D;;AAE7D;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;AACA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AA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AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,GAAG;;AAEH;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,mBAAmB;AACnB;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,GAAG;;AAEH;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,GAAG;;AAEH;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,kBAAkB,8BAA8B;;AAEhD;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,GAAG;;AAEH;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;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AEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,IAAI;;AAEJ;AACA;;AAEA,IAAI;;AAEJ;;AAEA,IAAI;;AAEJ;;AAEA,IAAI;;AAEJ;;AAEA,IAAI;;AAEJ;;AAEA,IAAI;;AAEJ;;AAEA,IAAI;;AAEJ;;AAEA,IAAI;;AAEJ;;AAEA;AACA;AACA;;AAEA;;AAEA,IAAI;;AAEJ;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;;AAGA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,GAAG;;AAEH;;AAEA,GAAG;;AAEH;;AAEA,GAAG;;AAEH;;AAEA,GAAG;;AAEH;;AAEA,GAAG;;AAEH;;AAEA,GAAG;;AAEH;;AAEA,GAAG;;AAEH;;AAEA,GAAG;;AAEH;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA,GAAG;;AAEH;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA,kEAAkE;;AAElE;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;A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;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,cAAc,qBAAqB;;AAEnC;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA,cAAc,qBAAqB;;AAEnC;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,cAAc,sBAAsB;;AAEpC,eAAe,qBAAqB;;AAEpC;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,cAAc,sBAAsB;;AAEpC,eAAe,qBAAqB;;AAEpC;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,aAAa,sBAAsB;;AAEnC;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA,cAAc,qBAAqB;;AAEnC;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,aAAa,sBAAsB;;AAEnC,cAAc,qBAAqB;;AAEnC;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA,aAAa,qBAAqB;;AAElC,cAAc,sBAAsB;;AAEpC;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,aAAa,qBAAqB;;AAElC,cAAc,sBAAsB;;AAEpC;;AAEA;AACA;AACA;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AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA,EAAE;;AAEF;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;;AAEA;;AAEA,wCAAwC,OAAO;;AAE/C;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,kBAAkB,2BAA2B;;AAE7C;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,iBAAiB;;AAEjB;;AAEA,oCAAoC;AACpC;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,iBAAiB;;AAEjB;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,iBAAiB;;AAEjB;;AAEA,yBAAyB;;AAEzB;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,iBAAiB;;AAEjB;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,oCAAoC;AACpC;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,iBAAiB;;AAEjB;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,oCAAoC;;AAEpC;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;;AAEA;;AAEA;;AAEA,UAAU;;AAEV;;AAEA;;AA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A;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,KAAK;;AAEL;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,EAAE;;AAEF;;AAEA;;AAEA,uCAAuC,OAAO;;AAE9C;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAE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EA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;;AAEA,EAAE;AACF;;AAEA;;AAEA,EAAE;AACF;;AAEA;;AAEA,EAAE;AACF;;AAEA;;AAEA,EAAE;AACF;;AAEA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA;;AAEA,CAAC;;AAED;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA;;AAEA,CAAC;;AAED;;AAEA;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA;;AAEA,CAAC;;AAED;;AAEA;;AAEA;AACA;;AAEA;;AAEA,CAAC;;AAED;;AAEA;;AAEA;;AAEA,EAAE;AACF;;AAEA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA;;AAEA,CAAC;;AAED;;AAEA;;AAEA;AACA;;AAEA;;AAEA,CAAC;;AAED;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA;;AAEA,CAAC;;AAED;;AAEA;AACA;;AAEA;AACA;;AAEA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;;AAEA,GAAG;AACH;;AAEA;;AAEA;AACA;;AAEA,CAAC;;AAED;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA,CAAC;;AAED;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;AACA,CAAC;;AAED;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA,CAAC;;AAED;;AAEA;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;;AAEA,EAAE;AACF;;AAEA;;AAEA;;AAEA,CAAC;;AAED;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA,CAAC;;AAED;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA,CAAC;;AAED;;AAEA;;AAEA;AACA;;AAEA;;AAEA,GAAG;AACH;;AAEA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA,CAAC;;AAED;;AAEA;AACA;;AAEA;AACA;;AAEA,GAAG;AACH;;AAEA;;AAEA;AACA;;AAEA,CAAC;;AAED;;AAEA;AACA;;AAEA;AACA;;AAEA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA;;AAEA,CAAC;;AAED;;AAEA;;AAEA;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;AACA;;AAEA,EAAE;AACF;;AAEA;;AAEA,EAAE;AACF;;AAEA;;AAEA,EAAE;AACF;;AAEA;;AAEA,EAAE;AACF;;AAEA;;AAEA;;AAEA,CAAC;;AAED;;AAEA;AACA;;AAEA;;AAEA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;;AAEA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;;AAEA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA;AACA,CAAC;;AAED;;AAEA;AACA;;AAEA;;AAEA,GAAG;AACH;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA,CAAC;;AAED;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA,EAAE;AACF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AACA;AACA;;AAEA,WAAW;;AAEX;;AAEA,SAAS;;AAET;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,WAAW;;AAEX;;AAEA,SAAS;;AAET;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,WAAW;;AAEX;;AAEA;;AAEA;;AAEA,KAAK;;AAEL;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;;AAEA;;AAEA,KAAK;;AAEL;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;;AAEA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;;AAEA;;AAEA;;AAEA,KAAK;;AAEL;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;;AAGA;;AAEA;;;AAGA,CAAC;AACD;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,KAAK;;AAEL;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,OAAO;AACP;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA;;AAEA,CAAC;AACD;AACA,kB;;;;;;AClvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;;AAGD;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,U;;AAEA,aAAa;;AAEb;;AAEA;;AAEA;AACA;AACA;;AAEA,OAAO;;AAEP;;AAEA,KAAK;;AAEL;;AAEA;;AAEA;AACA;AACA;;AAEA,OAAO;;AAEP;;AAEA,KAAK;;AAEL;AACA;AACA;AACA;AACA,4CAA4C,QAAQ;AACpD;AACA;AACA;AACA;AACA,KAAK;;AAEL;;;AAGA,iD;;AAEA;;AAEA,OAAO,0CAA0C;;AAEjD,yCAAyC,SAAS;AAClD;AACA;;AAEA,OAAO;;AAEP;AACA;AACA;;AAEA;;AAEA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA;;AAEA,CAAC;;;AAGD;;AAEA;AACA;AACA;AACA,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,cAAc;AACd;AACA;;AAEA;AACA;AACA,cAAc;AACd;AACA;;AAEA;AACA;AACA,cAAc;AACd;AACA;;AAEA;AACA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA;AACA,cAAc;AACd;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,mBAAmB,SAAS;AAC5B;AACA,qBAAqB,2BAA2B;AAChD;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA,mBAAmB,SAAS;AAC5B;AACA,qBAAqB,2BAA2B;AAChD;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA,mBAAmB,OAAO;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA,qBAAqB,OAAO;AAC5B;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA,qBAAqB,2BAA2B;AAChD;AACA;AACA;AACA,SAAS;;AAET;AACA,qBAAqB,QAAQ;AAC7B;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;;AAGA,CAAC;;;AAGD;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL,GAAG;;AAEH;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;;AAEA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+DAA+D;AAC/D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA,oBAAoB;AACpB;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,CAAC;;;AAGD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB,aAAa,gBAAgB;AAC7B;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,CAAC;AACD;AACA;;;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA,+BAA+B;AAC/B,OAAO;AACP;AACA;AACA;;AAEA,KAAK;;AAEL;;AAEA;;AAEA;;;AAGA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA,WAAW;AACX;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,SAAS;;AAET;AACA;AACA;AACA,mBAAmB,OAAO;AAC1B;AACA,qBAAqB,iCAAiC;AACtD;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA,mBAAmB,OAAO;AAC1B;AACA,qBAAqB,iCAAiC;AACtD;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA,mBAAmB,OAAO;AAC1B;AACA;AACA;AACA,qBAAqB,iCAAiC;AACtD;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;;AAEA,CAAC;AACD;;;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA,QAAQ,OAAO;AACf;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,KAAK;;AAEL;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AA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A;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;;AAGA;;AAEA;;;AAGA,CAAC;AACD;;;AAGA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,GAAG;;AAEH;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB;AACA,aAAa,QAAQ;AACrB,aAAa,YAAY;AACzB,aAAa,QAAQ;AACrB;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;;;AAGL;;AAEA;AACA;;AAEA,KAAK;;AAEL,qBAAqB;;AAErB;;AAEA;AACA;AACA;;AAEA;AACA;;;AAGA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA,aAAa;;AAEb;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA,WAAW;;AAEX;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;;AAEA;;AAEA,SAAS;;AAET;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;;AAGA,OAAO;;;AAGP;AACA,KAAK;;AAEL;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;;AAGA;AACA;;AAEA;;AAEA,2CAA2C,mBAAmB;AAC9D,2DAA2D,kBAAkB,EAAE;AAC/E,qDAAqD,mBAAmB;AACxE,sDAAsD,mBAAmB;AACzE;;;AAGA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA,GAAG;;AAEH;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,qBAAqB,2BAA2B;AAChD;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAAS;;AAET;AACA;AACA;AACA,qBAAqB,gCAAgC;AACrD;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAAS;;AAET;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX,SAAS;;AAET;;AAEA;AACA;AACA;;AAEA,SAAS;;AAET;AACA;AACA,qBAAqB,YAAY;AACjC,oBAAoB,MAAM;AAC1B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,gCAAgC;;AAEhC;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,wCAAwC;;AAExC;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA,SAAS;;AAET;AACA;AACA,SAAS;;AAET;AACA;AACA,SAAS;;AAET;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,aAAa;;AAEb;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,aAAa;AACb;;AAEA;AACA;AACA;;AAEA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA,mBAAmB,UAAU;AAC7B,oBAAoB,MAAM;AAC1B;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;;AAEA,SAAS;;AAET;AACA,qBAAqB,YAAY;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA,qBAAqB,OAAO;AAC5B;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA,WAAW;;AAEX;;AAEA,SAAS;;AAET;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA,SAAS;;AAET;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA,SAAS;;AAET;;AAEA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,WAAW;;AAEX;AACA;AACA,WAAW;;AAEX;AACA;AACA;;;AAGA,SAAS;;AAET;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,KAAK;;AAEL;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA,OAAO;;AAEP;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA;;AAEA,KAAK;;AAEL;AACA;;AAEA;AACA,WAAW,wEAAwE;;AAEnF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,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AEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,6BAA6B;AAC7B;AACA;AACA,KAAK;;AAEL;;AAEA;;AAEA;AACA;AACA;AACA;AACA,SAAS;;AAET,KAAK;;AAEL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA,KAAK;;AAEL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;;AAGA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,0BAA0B;AAC1B;AACA,aAAa;;AAEb;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,WAAW;;AAEX;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA,wGAAwG;AACxG,KAAK;AACL;;AAEA;AACA;AACA,6JAA6J;AAC7J,0JAA0J;AAC1J,qJAAqJ;AACrJ,sJAAsJ;AACtJ,kJAAkJ;AAClJ;;;AAGA;;AAEA,CAAC;AACD;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;;AAGA;;AAEA;;AAEA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA,GAAG;;AAEH;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA,KAAK;;AAEL;;AAEA;AACA;;AAEA;;AAEA,GAAG;;AAEH;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA,OAAO;;AAEP;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,KAAK;;AAEL;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA,OAAO;;AAEP;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,KAAK;;AAEL;;AAEA;;AAEA;;AAEA;;AAEA,KAAK;;AAEL;;AAEA,KAAK;;AAEL;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;;AAEA;;AAEA;;AAEA,CAAC;AACD;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,KAAK;;AAEL;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,OAAO;AACP;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA;;AAEA,CAAC;AACD;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,CAAC;AACD;;;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;;AAGL;AACA;;AAEA;AACA;AACA;AACA,KAAK;;;AAGL;;AAEA;;AAEA;;;;AAIA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,KAAK;;AAEL;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,CAAC;AACD;AACA;AACA,kB;;;;;;AC3kHA,0E;;;;;;ACAA,qE;;;;;;ACAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,iBAAiB,yBAAyB;AAC1C,iBAAiB;AACjB,GAAG;AACH;AACA,sBAAsB;;AAEtB,kBAAkB;;AAElB,gBAAgB;AAChB,gFAAgF;;AAEhF,MAAM;AACN;AACA;AACA,2BAA2B;;AAE3B,gCAAgC;;AAEhC,sBAAsB;;AAEtB,kBAAkB;;AAElB,+CAA+C;AAC/C,sCAAsC;;AAEtC,MAAM;AACN;AACA;;;;;;;ACnCA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,E;;;;;;AClBA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA,OAAO;;AAEP;AACA;;AAEA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","file":"bundle.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 44);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap c0ef4666137c2c569142","// Polyfills\n\nif ( Number.EPSILON === undefined ) {\n\n\tNumber.EPSILON = Math.pow( 2, - 52 );\n\n}\n\n//\n\nif ( Math.sign === undefined ) {\n\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign\n\n\tMath.sign = function ( x ) {\n\n\t\treturn ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : + x;\n\n\t};\n\n}\n\nif ( Function.prototype.name === undefined ) {\n\n\t// Missing in IE9-11.\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name\n\n\tObject.defineProperty( Function.prototype, 'name', {\n\n\t\tget: function () {\n\n\t\t\treturn this.toString().match( /^\\s*function\\s*([^\\(\\s]*)/ )[ 1 ];\n\n\t\t}\n\n\t} );\n\n}\n\nif ( Object.assign === undefined ) {\n\n\t// Missing in IE.\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign\n\n\t( function () {\n\n\t\tObject.assign = function ( target ) {\n\n\t\t\t'use strict';\n\n\t\t\tif ( target === undefined || target === null ) {\n\n\t\t\t\tthrow new TypeError( 'Cannot convert undefined or null to object' );\n\n\t\t\t}\n\n\t\t\tvar output = Object( target );\n\n\t\t\tfor ( var index = 1; index < arguments.length; index ++ ) {\n\n\t\t\t\tvar source = arguments[ index ];\n\n\t\t\t\tif ( source !== undefined && source !== null ) {\n\n\t\t\t\t\tfor ( var nextKey in source ) {\n\n\t\t\t\t\t\tif ( Object.prototype.hasOwnProperty.call( source, nextKey ) ) {\n\n\t\t\t\t\t\t\toutput[ nextKey ] = source[ nextKey ];\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn output;\n\n\t\t};\n\n\t} )();\n\n}\n\n/**\n * https://github.com/mrdoob/eventdispatcher.js/\n */\n\nfunction EventDispatcher() {}\n\nEventDispatcher.prototype = {\n\n\taddEventListener: function ( type, listener ) {\n\n\t\tif ( this._listeners === undefined ) this._listeners = {};\n\n\t\tvar listeners = this._listeners;\n\n\t\tif ( listeners[ type ] === undefined ) {\n\n\t\t\tlisteners[ type ] = [];\n\n\t\t}\n\n\t\tif ( listeners[ type ].indexOf( listener ) === - 1 ) {\n\n\t\t\tlisteners[ type ].push( listener );\n\n\t\t}\n\n\t},\n\n\thasEventListener: function ( type, listener ) {\n\n\t\tif ( this._listeners === undefined ) return false;\n\n\t\tvar listeners = this._listeners;\n\n\t\treturn listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1;\n\n\t},\n\n\tremoveEventListener: function ( type, listener ) {\n\n\t\tif ( this._listeners === undefined ) return;\n\n\t\tvar listeners = this._listeners;\n\t\tvar listenerArray = listeners[ type ];\n\n\t\tif ( listenerArray !== undefined ) {\n\n\t\t\tvar index = listenerArray.indexOf( listener );\n\n\t\t\tif ( index !== - 1 ) {\n\n\t\t\t\tlistenerArray.splice( index, 1 );\n\n\t\t\t}\n\n\t\t}\n\n\t},\n\n\tdispatchEvent: function ( event ) {\n\n\t\tif ( this._listeners === undefined ) return;\n\n\t\tvar listeners = this._listeners;\n\t\tvar listenerArray = listeners[ event.type ];\n\n\t\tif ( listenerArray !== undefined ) {\n\n\t\t\tevent.target = this;\n\n\t\t\tvar array = [], i = 0;\n\t\t\tvar length = listenerArray.length;\n\n\t\t\tfor ( i = 0; i < length; i ++ ) {\n\n\t\t\t\tarray[ i ] = listenerArray[ i ];\n\n\t\t\t}\n\n\t\t\tfor ( i = 0; i < length; i ++ ) {\n\n\t\t\t\tarray[ i ].call( this, event );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n};\n\nvar REVISION = '84';\nvar MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };\nvar CullFaceNone = 0;\nvar CullFaceBack = 1;\nvar CullFaceFront = 2;\nvar CullFaceFrontBack = 3;\nvar FrontFaceDirectionCW = 0;\nvar FrontFaceDirectionCCW = 1;\nvar BasicShadowMap = 0;\nvar PCFShadowMap = 1;\nvar PCFSoftShadowMap = 2;\nvar FrontSide = 0;\nvar BackSide = 1;\nvar DoubleSide = 2;\nvar FlatShading = 1;\nvar SmoothShading = 2;\nvar NoColors = 0;\nvar FaceColors = 1;\nvar VertexColors = 2;\nvar NoBlending = 0;\nvar NormalBlending = 1;\nvar AdditiveBlending = 2;\nvar SubtractiveBlending = 3;\nvar MultiplyBlending = 4;\nvar CustomBlending = 5;\nvar AddEquation = 100;\nvar SubtractEquation = 101;\nvar ReverseSubtractEquation = 102;\nvar MinEquation = 103;\nvar MaxEquation = 104;\nvar ZeroFactor = 200;\nvar OneFactor = 201;\nvar SrcColorFactor = 202;\nvar OneMinusSrcColorFactor = 203;\nvar SrcAlphaFactor = 204;\nvar OneMinusSrcAlphaFactor = 205;\nvar DstAlphaFactor = 206;\nvar OneMinusDstAlphaFactor = 207;\nvar DstColorFactor = 208;\nvar OneMinusDstColorFactor = 209;\nvar SrcAlphaSaturateFactor = 210;\nvar NeverDepth = 0;\nvar AlwaysDepth = 1;\nvar LessDepth = 2;\nvar LessEqualDepth = 3;\nvar EqualDepth = 4;\nvar GreaterEqualDepth = 5;\nvar GreaterDepth = 6;\nvar NotEqualDepth = 7;\nvar MultiplyOperation = 0;\nvar MixOperation = 1;\nvar AddOperation = 2;\nvar NoToneMapping = 0;\nvar LinearToneMapping = 1;\nvar ReinhardToneMapping = 2;\nvar Uncharted2ToneMapping = 3;\nvar CineonToneMapping = 4;\nvar UVMapping = 300;\nvar CubeReflectionMapping = 301;\nvar CubeRefractionMapping = 302;\nvar EquirectangularReflectionMapping = 303;\nvar EquirectangularRefractionMapping = 304;\nvar SphericalReflectionMapping = 305;\nvar CubeUVReflectionMapping = 306;\nvar CubeUVRefractionMapping = 307;\nvar RepeatWrapping = 1000;\nvar ClampToEdgeWrapping = 1001;\nvar MirroredRepeatWrapping = 1002;\nvar NearestFilter = 1003;\nvar NearestMipMapNearestFilter = 1004;\nvar NearestMipMapLinearFilter = 1005;\nvar LinearFilter = 1006;\nvar LinearMipMapNearestFilter = 1007;\nvar LinearMipMapLinearFilter = 1008;\nvar UnsignedByteType = 1009;\nvar ByteType = 1010;\nvar ShortType = 1011;\nvar UnsignedShortType = 1012;\nvar IntType = 1013;\nvar UnsignedIntType = 1014;\nvar FloatType = 1015;\nvar HalfFloatType = 1016;\nvar UnsignedShort4444Type = 1017;\nvar UnsignedShort5551Type = 1018;\nvar UnsignedShort565Type = 1019;\nvar UnsignedInt248Type = 1020;\nvar AlphaFormat = 1021;\nvar RGBFormat = 1022;\nvar RGBAFormat = 1023;\nvar LuminanceFormat = 1024;\nvar LuminanceAlphaFormat = 1025;\nvar RGBEFormat = RGBAFormat;\nvar DepthFormat = 1026;\nvar DepthStencilFormat = 1027;\nvar RGB_S3TC_DXT1_Format = 2001;\nvar RGBA_S3TC_DXT1_Format = 2002;\nvar RGBA_S3TC_DXT3_Format = 2003;\nvar RGBA_S3TC_DXT5_Format = 2004;\nvar RGB_PVRTC_4BPPV1_Format = 2100;\nvar RGB_PVRTC_2BPPV1_Format = 2101;\nvar RGBA_PVRTC_4BPPV1_Format = 2102;\nvar RGBA_PVRTC_2BPPV1_Format = 2103;\nvar RGB_ETC1_Format = 2151;\nvar LoopOnce = 2200;\nvar LoopRepeat = 2201;\nvar LoopPingPong = 2202;\nvar InterpolateDiscrete = 2300;\nvar InterpolateLinear = 2301;\nvar InterpolateSmooth = 2302;\nvar ZeroCurvatureEnding = 2400;\nvar ZeroSlopeEnding = 2401;\nvar WrapAroundEnding = 2402;\nvar TrianglesDrawMode = 0;\nvar TriangleStripDrawMode = 1;\nvar TriangleFanDrawMode = 2;\nvar LinearEncoding = 3000;\nvar sRGBEncoding = 3001;\nvar GammaEncoding = 3007;\nvar RGBEEncoding = 3002;\nvar LogLuvEncoding = 3003;\nvar RGBM7Encoding = 3004;\nvar RGBM16Encoding = 3005;\nvar RGBDEncoding = 3006;\nvar BasicDepthPacking = 3200;\nvar RGBADepthPacking = 3201;\n\n/**\n * @author alteredq / http://alteredqualia.com/\n * @author mrdoob / http://mrdoob.com/\n */\n\nvar _Math = {\n\n\tDEG2RAD: Math.PI / 180,\n\tRAD2DEG: 180 / Math.PI,\n\n\tgenerateUUID: function () {\n\n\t\t// http://www.broofa.com/Tools/Math.uuid.htm\n\n\t\tvar chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' );\n\t\tvar uuid = new Array( 36 );\n\t\tvar rnd = 0, r;\n\n\t\treturn function generateUUID() {\n\n\t\t\tfor ( var i = 0; i < 36; i ++ ) {\n\n\t\t\t\tif ( i === 8 || i === 13 || i === 18 || i === 23 ) {\n\n\t\t\t\t\tuuid[ i ] = '-';\n\n\t\t\t\t} else if ( i === 14 ) {\n\n\t\t\t\t\tuuid[ i ] = '4';\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0;\n\t\t\t\t\tr = rnd & 0xf;\n\t\t\t\t\trnd = rnd >> 4;\n\t\t\t\t\tuuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn uuid.join( '' );\n\n\t\t};\n\n\t}(),\n\n\tclamp: function ( value, min, max ) {\n\n\t\treturn Math.max( min, Math.min( max, value ) );\n\n\t},\n\n\t// compute euclidian modulo of m % n\n\t// https://en.wikipedia.org/wiki/Modulo_operation\n\n\teuclideanModulo: function ( n, m ) {\n\n\t\treturn ( ( n % m ) + m ) % m;\n\n\t},\n\n\t// Linear mapping from range to range \n\n\tmapLinear: function ( x, a1, a2, b1, b2 ) {\n\n\t\treturn b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );\n\n\t},\n\n\t// https://en.wikipedia.org/wiki/Linear_interpolation\n\n\tlerp: function ( x, y, t ) {\n\n\t\treturn ( 1 - t ) * x + t * y;\n\n\t},\n\n\t// http://en.wikipedia.org/wiki/Smoothstep\n\n\tsmoothstep: function ( x, min, max ) {\n\n\t\tif ( x <= min ) return 0;\n\t\tif ( x >= max ) return 1;\n\n\t\tx = ( x - min ) / ( max - min );\n\n\t\treturn x * x * ( 3 - 2 * x );\n\n\t},\n\n\tsmootherstep: function ( x, min, max ) {\n\n\t\tif ( x <= min ) return 0;\n\t\tif ( x >= max ) return 1;\n\n\t\tx = ( x - min ) / ( max - min );\n\n\t\treturn x * x * x * ( x * ( x * 6 - 15 ) + 10 );\n\n\t},\n\n\t// Random integer from interval\n\n\trandInt: function ( low, high ) {\n\n\t\treturn low + Math.floor( Math.random() * ( high - low + 1 ) );\n\n\t},\n\n\t// Random float from interval\n\n\trandFloat: function ( low, high ) {\n\n\t\treturn low + Math.random() * ( high - low );\n\n\t},\n\n\t// Random float from <-range/2, range/2> interval\n\n\trandFloatSpread: function ( range ) {\n\n\t\treturn range * ( 0.5 - Math.random() );\n\n\t},\n\n\tdegToRad: function ( degrees ) {\n\n\t\treturn degrees * _Math.DEG2RAD;\n\n\t},\n\n\tradToDeg: function ( radians ) {\n\n\t\treturn radians * _Math.RAD2DEG;\n\n\t},\n\n\tisPowerOfTwo: function ( value ) {\n\n\t\treturn ( value & ( value - 1 ) ) === 0 && value !== 0;\n\n\t},\n\n\tnearestPowerOfTwo: function ( value ) {\n\n\t\treturn Math.pow( 2, Math.round( Math.log( value ) / Math.LN2 ) );\n\n\t},\n\n\tnextPowerOfTwo: function ( value ) {\n\n\t\tvalue --;\n\t\tvalue |= value >> 1;\n\t\tvalue |= value >> 2;\n\t\tvalue |= value >> 4;\n\t\tvalue |= value >> 8;\n\t\tvalue |= value >> 16;\n\t\tvalue ++;\n\n\t\treturn value;\n\n\t}\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author philogb / http://blog.thejit.org/\n * @author egraether / http://egraether.com/\n * @author zz85 / http://www.lab4games.net/zz85/blog\n */\n\nfunction Vector2( x, y ) {\n\n\tthis.x = x || 0;\n\tthis.y = y || 0;\n\n}\n\nVector2.prototype = {\n\n\tconstructor: Vector2,\n\n\tisVector2: true,\n\n\tget width() {\n\n\t\treturn this.x;\n\n\t},\n\n\tset width( value ) {\n\n\t\tthis.x = value;\n\n\t},\n\n\tget height() {\n\n\t\treturn this.y;\n\n\t},\n\n\tset height( value ) {\n\n\t\tthis.y = value;\n\n\t},\n\n\t//\n\n\tset: function ( x, y ) {\n\n\t\tthis.x = x;\n\t\tthis.y = y;\n\n\t\treturn this;\n\n\t},\n\n\tsetScalar: function ( scalar ) {\n\n\t\tthis.x = scalar;\n\t\tthis.y = scalar;\n\n\t\treturn this;\n\n\t},\n\n\tsetX: function ( x ) {\n\n\t\tthis.x = x;\n\n\t\treturn this;\n\n\t},\n\n\tsetY: function ( y ) {\n\n\t\tthis.y = y;\n\n\t\treturn this;\n\n\t},\n\n\tsetComponent: function ( index, value ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: this.x = value; break;\n\t\t\tcase 1: this.y = value; break;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tgetComponent: function ( index ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: return this.x;\n\t\t\tcase 1: return this.y;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor( this.x, this.y );\n\n\t},\n\n\tcopy: function ( v ) {\n\n\t\tthis.x = v.x;\n\t\tthis.y = v.y;\n\n\t\treturn this;\n\n\t},\n\n\tadd: function ( v, w ) {\n\n\t\tif ( w !== undefined ) {\n\n\t\t\tconsole.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );\n\t\t\treturn this.addVectors( v, w );\n\n\t\t}\n\n\t\tthis.x += v.x;\n\t\tthis.y += v.y;\n\n\t\treturn this;\n\n\t},\n\n\taddScalar: function ( s ) {\n\n\t\tthis.x += s;\n\t\tthis.y += s;\n\n\t\treturn this;\n\n\t},\n\n\taddVectors: function ( a, b ) {\n\n\t\tthis.x = a.x + b.x;\n\t\tthis.y = a.y + b.y;\n\n\t\treturn this;\n\n\t},\n\n\taddScaledVector: function ( v, s ) {\n\n\t\tthis.x += v.x * s;\n\t\tthis.y += v.y * s;\n\n\t\treturn this;\n\n\t},\n\n\tsub: function ( v, w ) {\n\n\t\tif ( w !== undefined ) {\n\n\t\t\tconsole.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );\n\t\t\treturn this.subVectors( v, w );\n\n\t\t}\n\n\t\tthis.x -= v.x;\n\t\tthis.y -= v.y;\n\n\t\treturn this;\n\n\t},\n\n\tsubScalar: function ( s ) {\n\n\t\tthis.x -= s;\n\t\tthis.y -= s;\n\n\t\treturn this;\n\n\t},\n\n\tsubVectors: function ( a, b ) {\n\n\t\tthis.x = a.x - b.x;\n\t\tthis.y = a.y - b.y;\n\n\t\treturn this;\n\n\t},\n\n\tmultiply: function ( v ) {\n\n\t\tthis.x *= v.x;\n\t\tthis.y *= v.y;\n\n\t\treturn this;\n\n\t},\n\n\tmultiplyScalar: function ( scalar ) {\n\n\t\tif ( isFinite( scalar ) ) {\n\n\t\t\tthis.x *= scalar;\n\t\t\tthis.y *= scalar;\n\n\t\t} else {\n\n\t\t\tthis.x = 0;\n\t\t\tthis.y = 0;\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tdivide: function ( v ) {\n\n\t\tthis.x /= v.x;\n\t\tthis.y /= v.y;\n\n\t\treturn this;\n\n\t},\n\n\tdivideScalar: function ( scalar ) {\n\n\t\treturn this.multiplyScalar( 1 / scalar );\n\n\t},\n\n\tmin: function ( v ) {\n\n\t\tthis.x = Math.min( this.x, v.x );\n\t\tthis.y = Math.min( this.y, v.y );\n\n\t\treturn this;\n\n\t},\n\n\tmax: function ( v ) {\n\n\t\tthis.x = Math.max( this.x, v.x );\n\t\tthis.y = Math.max( this.y, v.y );\n\n\t\treturn this;\n\n\t},\n\n\tclamp: function ( min, max ) {\n\n\t\t// This function assumes min < max, if this assumption isn't true it will not operate correctly\n\n\t\tthis.x = Math.max( min.x, Math.min( max.x, this.x ) );\n\t\tthis.y = Math.max( min.y, Math.min( max.y, this.y ) );\n\n\t\treturn this;\n\n\t},\n\n\tclampScalar: function () {\n\n\t\tvar min, max;\n\n\t\treturn function clampScalar( minVal, maxVal ) {\n\n\t\t\tif ( min === undefined ) {\n\n\t\t\t\tmin = new Vector2();\n\t\t\t\tmax = new Vector2();\n\n\t\t\t}\n\n\t\t\tmin.set( minVal, minVal );\n\t\t\tmax.set( maxVal, maxVal );\n\n\t\t\treturn this.clamp( min, max );\n\n\t\t};\n\n\t}(),\n\n\tclampLength: function ( min, max ) {\n\n\t\tvar length = this.length();\n\n\t\treturn this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length );\n\n\t},\n\n\tfloor: function () {\n\n\t\tthis.x = Math.floor( this.x );\n\t\tthis.y = Math.floor( this.y );\n\n\t\treturn this;\n\n\t},\n\n\tceil: function () {\n\n\t\tthis.x = Math.ceil( this.x );\n\t\tthis.y = Math.ceil( this.y );\n\n\t\treturn this;\n\n\t},\n\n\tround: function () {\n\n\t\tthis.x = Math.round( this.x );\n\t\tthis.y = Math.round( this.y );\n\n\t\treturn this;\n\n\t},\n\n\troundToZero: function () {\n\n\t\tthis.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );\n\t\tthis.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );\n\n\t\treturn this;\n\n\t},\n\n\tnegate: function () {\n\n\t\tthis.x = - this.x;\n\t\tthis.y = - this.y;\n\n\t\treturn this;\n\n\t},\n\n\tdot: function ( v ) {\n\n\t\treturn this.x * v.x + this.y * v.y;\n\n\t},\n\n\tlengthSq: function () {\n\n\t\treturn this.x * this.x + this.y * this.y;\n\n\t},\n\n\tlength: function () {\n\n\t\treturn Math.sqrt( this.x * this.x + this.y * this.y );\n\n\t},\n\n\tlengthManhattan: function() {\n\n\t\treturn Math.abs( this.x ) + Math.abs( this.y );\n\n\t},\n\n\tnormalize: function () {\n\n\t\treturn this.divideScalar( this.length() );\n\n\t},\n\n\tangle: function () {\n\n\t\t// computes the angle in radians with respect to the positive x-axis\n\n\t\tvar angle = Math.atan2( this.y, this.x );\n\n\t\tif ( angle < 0 ) angle += 2 * Math.PI;\n\n\t\treturn angle;\n\n\t},\n\n\tdistanceTo: function ( v ) {\n\n\t\treturn Math.sqrt( this.distanceToSquared( v ) );\n\n\t},\n\n\tdistanceToSquared: function ( v ) {\n\n\t\tvar dx = this.x - v.x, dy = this.y - v.y;\n\t\treturn dx * dx + dy * dy;\n\n\t},\n\n\tdistanceToManhattan: function ( v ) {\n\n\t\treturn Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );\n\n\t},\n\n\tsetLength: function ( length ) {\n\n\t\treturn this.multiplyScalar( length / this.length() );\n\n\t},\n\n\tlerp: function ( v, alpha ) {\n\n\t\tthis.x += ( v.x - this.x ) * alpha;\n\t\tthis.y += ( v.y - this.y ) * alpha;\n\n\t\treturn this;\n\n\t},\n\n\tlerpVectors: function ( v1, v2, alpha ) {\n\n\t\treturn this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );\n\n\t},\n\n\tequals: function ( v ) {\n\n\t\treturn ( ( v.x === this.x ) && ( v.y === this.y ) );\n\n\t},\n\n\tfromArray: function ( array, offset ) {\n\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tthis.x = array[ offset ];\n\t\tthis.y = array[ offset + 1 ];\n\n\t\treturn this;\n\n\t},\n\n\ttoArray: function ( array, offset ) {\n\n\t\tif ( array === undefined ) array = [];\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tarray[ offset ] = this.x;\n\t\tarray[ offset + 1 ] = this.y;\n\n\t\treturn array;\n\n\t},\n\n\tfromBufferAttribute: function ( attribute, index, offset ) {\n\n\t\tif ( offset !== undefined ) {\n\n\t\t\tconsole.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' );\n\n\t\t}\n\n\t\tthis.x = attribute.getX( index );\n\t\tthis.y = attribute.getY( index );\n\n\t\treturn this;\n\n\t},\n\n\trotateAround: function ( center, angle ) {\n\n\t\tvar c = Math.cos( angle ), s = Math.sin( angle );\n\n\t\tvar x = this.x - center.x;\n\t\tvar y = this.y - center.y;\n\n\t\tthis.x = x * c - y * s + center.x;\n\t\tthis.y = x * s + y * c + center.y;\n\n\t\treturn this;\n\n\t}\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author alteredq / http://alteredqualia.com/\n * @author szimek / https://github.com/szimek/\n */\n\nvar textureId = 0;\n\nfunction Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {\n\n\tObject.defineProperty( this, 'id', { value: textureId ++ } );\n\n\tthis.uuid = _Math.generateUUID();\n\n\tthis.name = '';\n\n\tthis.image = image !== undefined ? image : Texture.DEFAULT_IMAGE;\n\tthis.mipmaps = [];\n\n\tthis.mapping = mapping !== undefined ? mapping : Texture.DEFAULT_MAPPING;\n\n\tthis.wrapS = wrapS !== undefined ? wrapS : ClampToEdgeWrapping;\n\tthis.wrapT = wrapT !== undefined ? wrapT : ClampToEdgeWrapping;\n\n\tthis.magFilter = magFilter !== undefined ? magFilter : LinearFilter;\n\tthis.minFilter = minFilter !== undefined ? minFilter : LinearMipMapLinearFilter;\n\n\tthis.anisotropy = anisotropy !== undefined ? anisotropy : 1;\n\n\tthis.format = format !== undefined ? format : RGBAFormat;\n\tthis.type = type !== undefined ? type : UnsignedByteType;\n\n\tthis.offset = new Vector2( 0, 0 );\n\tthis.repeat = new Vector2( 1, 1 );\n\n\tthis.generateMipmaps = true;\n\tthis.premultiplyAlpha = false;\n\tthis.flipY = true;\n\tthis.unpackAlignment = 4;\t// valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)\n\n\n\t// Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.\n\t//\n\t// Also changing the encoding after already used by a Material will not automatically make the Material\n\t// update. You need to explicitly call Material.needsUpdate to trigger it to recompile.\n\tthis.encoding = encoding !== undefined ? encoding : LinearEncoding;\n\n\tthis.version = 0;\n\tthis.onUpdate = null;\n\n}\n\nTexture.DEFAULT_IMAGE = undefined;\nTexture.DEFAULT_MAPPING = UVMapping;\n\nTexture.prototype = {\n\n\tconstructor: Texture,\n\n\tisTexture: true,\n\n\tset needsUpdate( value ) {\n\n\t\tif ( value === true ) this.version ++;\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor().copy( this );\n\n\t},\n\n\tcopy: function ( source ) {\n\n\t\tthis.image = source.image;\n\t\tthis.mipmaps = source.mipmaps.slice( 0 );\n\n\t\tthis.mapping = source.mapping;\n\n\t\tthis.wrapS = source.wrapS;\n\t\tthis.wrapT = source.wrapT;\n\n\t\tthis.magFilter = source.magFilter;\n\t\tthis.minFilter = source.minFilter;\n\n\t\tthis.anisotropy = source.anisotropy;\n\n\t\tthis.format = source.format;\n\t\tthis.type = source.type;\n\n\t\tthis.offset.copy( source.offset );\n\t\tthis.repeat.copy( source.repeat );\n\n\t\tthis.generateMipmaps = source.generateMipmaps;\n\t\tthis.premultiplyAlpha = source.premultiplyAlpha;\n\t\tthis.flipY = source.flipY;\n\t\tthis.unpackAlignment = source.unpackAlignment;\n\t\tthis.encoding = source.encoding;\n\n\t\treturn this;\n\n\t},\n\n\ttoJSON: function ( meta ) {\n\n\t\tif ( meta.textures[ this.uuid ] !== undefined ) {\n\n\t\t\treturn meta.textures[ this.uuid ];\n\n\t\t}\n\n\t\tfunction getDataURL( image ) {\n\n\t\t\tvar canvas;\n\n\t\t\tif ( image.toDataURL !== undefined ) {\n\n\t\t\t\tcanvas = image;\n\n\t\t\t} else {\n\n\t\t\t\tcanvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );\n\t\t\t\tcanvas.width = image.width;\n\t\t\t\tcanvas.height = image.height;\n\n\t\t\t\tcanvas.getContext( '2d' ).drawImage( image, 0, 0, image.width, image.height );\n\n\t\t\t}\n\n\t\t\tif ( canvas.width > 2048 || canvas.height > 2048 ) {\n\n\t\t\t\treturn canvas.toDataURL( 'image/jpeg', 0.6 );\n\n\t\t\t} else {\n\n\t\t\t\treturn canvas.toDataURL( 'image/png' );\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar output = {\n\t\t\tmetadata: {\n\t\t\t\tversion: 4.4,\n\t\t\t\ttype: 'Texture',\n\t\t\t\tgenerator: 'Texture.toJSON'\n\t\t\t},\n\n\t\t\tuuid: this.uuid,\n\t\t\tname: this.name,\n\n\t\t\tmapping: this.mapping,\n\n\t\t\trepeat: [ this.repeat.x, this.repeat.y ],\n\t\t\toffset: [ this.offset.x, this.offset.y ],\n\t\t\twrap: [ this.wrapS, this.wrapT ],\n\n\t\t\tminFilter: this.minFilter,\n\t\t\tmagFilter: this.magFilter,\n\t\t\tanisotropy: this.anisotropy,\n\n\t\t\tflipY: this.flipY\n\t\t};\n\n\t\tif ( this.image !== undefined ) {\n\n\t\t\t// TODO: Move to THREE.Image\n\n\t\t\tvar image = this.image;\n\n\t\t\tif ( image.uuid === undefined ) {\n\n\t\t\t\timage.uuid = _Math.generateUUID(); // UGH\n\n\t\t\t}\n\n\t\t\tif ( meta.images[ image.uuid ] === undefined ) {\n\n\t\t\t\tmeta.images[ image.uuid ] = {\n\t\t\t\t\tuuid: image.uuid,\n\t\t\t\t\turl: getDataURL( image )\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t\toutput.image = image.uuid;\n\n\t\t}\n\n\t\tmeta.textures[ this.uuid ] = output;\n\n\t\treturn output;\n\n\t},\n\n\tdispose: function () {\n\n\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t},\n\n\ttransformUv: function ( uv ) {\n\n\t\tif ( this.mapping !== UVMapping ) return;\n\n\t\tuv.multiply( this.repeat );\n\t\tuv.add( this.offset );\n\n\t\tif ( uv.x < 0 || uv.x > 1 ) {\n\n\t\t\tswitch ( this.wrapS ) {\n\n\t\t\t\tcase RepeatWrapping:\n\n\t\t\t\t\tuv.x = uv.x - Math.floor( uv.x );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase ClampToEdgeWrapping:\n\n\t\t\t\t\tuv.x = uv.x < 0 ? 0 : 1;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase MirroredRepeatWrapping:\n\n\t\t\t\t\tif ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {\n\n\t\t\t\t\t\tuv.x = Math.ceil( uv.x ) - uv.x;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tuv.x = uv.x - Math.floor( uv.x );\n\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( uv.y < 0 || uv.y > 1 ) {\n\n\t\t\tswitch ( this.wrapT ) {\n\n\t\t\t\tcase RepeatWrapping:\n\n\t\t\t\t\tuv.y = uv.y - Math.floor( uv.y );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase ClampToEdgeWrapping:\n\n\t\t\t\t\tuv.y = uv.y < 0 ? 0 : 1;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase MirroredRepeatWrapping:\n\n\t\t\t\t\tif ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {\n\n\t\t\t\t\t\tuv.y = Math.ceil( uv.y ) - uv.y;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tuv.y = uv.y - Math.floor( uv.y );\n\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( this.flipY ) {\n\n\t\t\tuv.y = 1 - uv.y;\n\n\t\t}\n\n\t}\n\n};\n\nObject.assign( Texture.prototype, EventDispatcher.prototype );\n\n/**\n * @author supereggbert / http://www.paulbrunt.co.uk/\n * @author philogb / http://blog.thejit.org/\n * @author mikael emtinger / http://gomo.se/\n * @author egraether / http://egraether.com/\n * @author WestLangley / http://github.com/WestLangley\n */\n\nfunction Vector4( x, y, z, w ) {\n\n\tthis.x = x || 0;\n\tthis.y = y || 0;\n\tthis.z = z || 0;\n\tthis.w = ( w !== undefined ) ? w : 1;\n\n}\n\nVector4.prototype = {\n\n\tconstructor: Vector4,\n\n\tisVector4: true,\n\n\tset: function ( x, y, z, w ) {\n\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.z = z;\n\t\tthis.w = w;\n\n\t\treturn this;\n\n\t},\n\n\tsetScalar: function ( scalar ) {\n\n\t\tthis.x = scalar;\n\t\tthis.y = scalar;\n\t\tthis.z = scalar;\n\t\tthis.w = scalar;\n\n\t\treturn this;\n\n\t},\n\n\tsetX: function ( x ) {\n\n\t\tthis.x = x;\n\n\t\treturn this;\n\n\t},\n\n\tsetY: function ( y ) {\n\n\t\tthis.y = y;\n\n\t\treturn this;\n\n\t},\n\n\tsetZ: function ( z ) {\n\n\t\tthis.z = z;\n\n\t\treturn this;\n\n\t},\n\n\tsetW: function ( w ) {\n\n\t\tthis.w = w;\n\n\t\treturn this;\n\n\t},\n\n\tsetComponent: function ( index, value ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: this.x = value; break;\n\t\t\tcase 1: this.y = value; break;\n\t\t\tcase 2: this.z = value; break;\n\t\t\tcase 3: this.w = value; break;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tgetComponent: function ( index ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: return this.x;\n\t\t\tcase 1: return this.y;\n\t\t\tcase 2: return this.z;\n\t\t\tcase 3: return this.w;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor( this.x, this.y, this.z, this.w );\n\n\t},\n\n\tcopy: function ( v ) {\n\n\t\tthis.x = v.x;\n\t\tthis.y = v.y;\n\t\tthis.z = v.z;\n\t\tthis.w = ( v.w !== undefined ) ? v.w : 1;\n\n\t\treturn this;\n\n\t},\n\n\tadd: function ( v, w ) {\n\n\t\tif ( w !== undefined ) {\n\n\t\t\tconsole.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );\n\t\t\treturn this.addVectors( v, w );\n\n\t\t}\n\n\t\tthis.x += v.x;\n\t\tthis.y += v.y;\n\t\tthis.z += v.z;\n\t\tthis.w += v.w;\n\n\t\treturn this;\n\n\t},\n\n\taddScalar: function ( s ) {\n\n\t\tthis.x += s;\n\t\tthis.y += s;\n\t\tthis.z += s;\n\t\tthis.w += s;\n\n\t\treturn this;\n\n\t},\n\n\taddVectors: function ( a, b ) {\n\n\t\tthis.x = a.x + b.x;\n\t\tthis.y = a.y + b.y;\n\t\tthis.z = a.z + b.z;\n\t\tthis.w = a.w + b.w;\n\n\t\treturn this;\n\n\t},\n\n\taddScaledVector: function ( v, s ) {\n\n\t\tthis.x += v.x * s;\n\t\tthis.y += v.y * s;\n\t\tthis.z += v.z * s;\n\t\tthis.w += v.w * s;\n\n\t\treturn this;\n\n\t},\n\n\tsub: function ( v, w ) {\n\n\t\tif ( w !== undefined ) {\n\n\t\t\tconsole.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );\n\t\t\treturn this.subVectors( v, w );\n\n\t\t}\n\n\t\tthis.x -= v.x;\n\t\tthis.y -= v.y;\n\t\tthis.z -= v.z;\n\t\tthis.w -= v.w;\n\n\t\treturn this;\n\n\t},\n\n\tsubScalar: function ( s ) {\n\n\t\tthis.x -= s;\n\t\tthis.y -= s;\n\t\tthis.z -= s;\n\t\tthis.w -= s;\n\n\t\treturn this;\n\n\t},\n\n\tsubVectors: function ( a, b ) {\n\n\t\tthis.x = a.x - b.x;\n\t\tthis.y = a.y - b.y;\n\t\tthis.z = a.z - b.z;\n\t\tthis.w = a.w - b.w;\n\n\t\treturn this;\n\n\t},\n\n\tmultiplyScalar: function ( scalar ) {\n\n\t\tif ( isFinite( scalar ) ) {\n\n\t\t\tthis.x *= scalar;\n\t\t\tthis.y *= scalar;\n\t\t\tthis.z *= scalar;\n\t\t\tthis.w *= scalar;\n\n\t\t} else {\n\n\t\t\tthis.x = 0;\n\t\t\tthis.y = 0;\n\t\t\tthis.z = 0;\n\t\t\tthis.w = 0;\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tapplyMatrix4: function ( m ) {\n\n\t\tvar x = this.x, y = this.y, z = this.z, w = this.w;\n\t\tvar e = m.elements;\n\n\t\tthis.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;\n\t\tthis.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;\n\t\tthis.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;\n\t\tthis.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;\n\n\t\treturn this;\n\n\t},\n\n\tdivideScalar: function ( scalar ) {\n\n\t\treturn this.multiplyScalar( 1 / scalar );\n\n\t},\n\n\tsetAxisAngleFromQuaternion: function ( q ) {\n\n\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm\n\n\t\t// q is assumed to be normalized\n\n\t\tthis.w = 2 * Math.acos( q.w );\n\n\t\tvar s = Math.sqrt( 1 - q.w * q.w );\n\n\t\tif ( s < 0.0001 ) {\n\n\t\t\t this.x = 1;\n\t\t\t this.y = 0;\n\t\t\t this.z = 0;\n\n\t\t} else {\n\n\t\t\t this.x = q.x / s;\n\t\t\t this.y = q.y / s;\n\t\t\t this.z = q.z / s;\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tsetAxisAngleFromRotationMatrix: function ( m ) {\n\n\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm\n\n\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\n\n\t\tvar angle, x, y, z,\t\t// variables for result\n\t\t\tepsilon = 0.01,\t\t// margin to allow for rounding errors\n\t\t\tepsilon2 = 0.1,\t\t// margin to distinguish between 0 and 180 degrees\n\n\t\t\tte = m.elements,\n\n\t\t\tm11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],\n\t\t\tm21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],\n\t\t\tm31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];\n\n\t\tif ( ( Math.abs( m12 - m21 ) < epsilon ) &&\n\t\t ( Math.abs( m13 - m31 ) < epsilon ) &&\n\t\t ( Math.abs( m23 - m32 ) < epsilon ) ) {\n\n\t\t\t// singularity found\n\t\t\t// first check for identity matrix which must have +1 for all terms\n\t\t\t// in leading diagonal and zero in other terms\n\n\t\t\tif ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&\n\t\t\t ( Math.abs( m13 + m31 ) < epsilon2 ) &&\n\t\t\t ( Math.abs( m23 + m32 ) < epsilon2 ) &&\n\t\t\t ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {\n\n\t\t\t\t// this singularity is identity matrix so angle = 0\n\n\t\t\t\tthis.set( 1, 0, 0, 0 );\n\n\t\t\t\treturn this; // zero angle, arbitrary axis\n\n\t\t\t}\n\n\t\t\t// otherwise this singularity is angle = 180\n\n\t\t\tangle = Math.PI;\n\n\t\t\tvar xx = ( m11 + 1 ) / 2;\n\t\t\tvar yy = ( m22 + 1 ) / 2;\n\t\t\tvar zz = ( m33 + 1 ) / 2;\n\t\t\tvar xy = ( m12 + m21 ) / 4;\n\t\t\tvar xz = ( m13 + m31 ) / 4;\n\t\t\tvar yz = ( m23 + m32 ) / 4;\n\n\t\t\tif ( ( xx > yy ) && ( xx > zz ) ) {\n\n\t\t\t\t// m11 is the largest diagonal term\n\n\t\t\t\tif ( xx < epsilon ) {\n\n\t\t\t\t\tx = 0;\n\t\t\t\t\ty = 0.707106781;\n\t\t\t\t\tz = 0.707106781;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tx = Math.sqrt( xx );\n\t\t\t\t\ty = xy / x;\n\t\t\t\t\tz = xz / x;\n\n\t\t\t\t}\n\n\t\t\t} else if ( yy > zz ) {\n\n\t\t\t\t// m22 is the largest diagonal term\n\n\t\t\t\tif ( yy < epsilon ) {\n\n\t\t\t\t\tx = 0.707106781;\n\t\t\t\t\ty = 0;\n\t\t\t\t\tz = 0.707106781;\n\n\t\t\t\t} else {\n\n\t\t\t\t\ty = Math.sqrt( yy );\n\t\t\t\t\tx = xy / y;\n\t\t\t\t\tz = yz / y;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// m33 is the largest diagonal term so base result on this\n\n\t\t\t\tif ( zz < epsilon ) {\n\n\t\t\t\t\tx = 0.707106781;\n\t\t\t\t\ty = 0.707106781;\n\t\t\t\t\tz = 0;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tz = Math.sqrt( zz );\n\t\t\t\t\tx = xz / z;\n\t\t\t\t\ty = yz / z;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.set( x, y, z, angle );\n\n\t\t\treturn this; // return 180 deg rotation\n\n\t\t}\n\n\t\t// as we have reached here there are no singularities so we can handle normally\n\n\t\tvar s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +\n\t\t ( m13 - m31 ) * ( m13 - m31 ) +\n\t\t ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize\n\n\t\tif ( Math.abs( s ) < 0.001 ) s = 1;\n\n\t\t// prevent divide by zero, should not happen if matrix is orthogonal and should be\n\t\t// caught by singularity test above, but I've left it in just in case\n\n\t\tthis.x = ( m32 - m23 ) / s;\n\t\tthis.y = ( m13 - m31 ) / s;\n\t\tthis.z = ( m21 - m12 ) / s;\n\t\tthis.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );\n\n\t\treturn this;\n\n\t},\n\n\tmin: function ( v ) {\n\n\t\tthis.x = Math.min( this.x, v.x );\n\t\tthis.y = Math.min( this.y, v.y );\n\t\tthis.z = Math.min( this.z, v.z );\n\t\tthis.w = Math.min( this.w, v.w );\n\n\t\treturn this;\n\n\t},\n\n\tmax: function ( v ) {\n\n\t\tthis.x = Math.max( this.x, v.x );\n\t\tthis.y = Math.max( this.y, v.y );\n\t\tthis.z = Math.max( this.z, v.z );\n\t\tthis.w = Math.max( this.w, v.w );\n\n\t\treturn this;\n\n\t},\n\n\tclamp: function ( min, max ) {\n\n\t\t// This function assumes min < max, if this assumption isn't true it will not operate correctly\n\n\t\tthis.x = Math.max( min.x, Math.min( max.x, this.x ) );\n\t\tthis.y = Math.max( min.y, Math.min( max.y, this.y ) );\n\t\tthis.z = Math.max( min.z, Math.min( max.z, this.z ) );\n\t\tthis.w = Math.max( min.w, Math.min( max.w, this.w ) );\n\n\t\treturn this;\n\n\t},\n\n\tclampScalar: function () {\n\n\t\tvar min, max;\n\n\t\treturn function clampScalar( minVal, maxVal ) {\n\n\t\t\tif ( min === undefined ) {\n\n\t\t\t\tmin = new Vector4();\n\t\t\t\tmax = new Vector4();\n\n\t\t\t}\n\n\t\t\tmin.set( minVal, minVal, minVal, minVal );\n\t\t\tmax.set( maxVal, maxVal, maxVal, maxVal );\n\n\t\t\treturn this.clamp( min, max );\n\n\t\t};\n\n\t}(),\n\n\tfloor: function () {\n\n\t\tthis.x = Math.floor( this.x );\n\t\tthis.y = Math.floor( this.y );\n\t\tthis.z = Math.floor( this.z );\n\t\tthis.w = Math.floor( this.w );\n\n\t\treturn this;\n\n\t},\n\n\tceil: function () {\n\n\t\tthis.x = Math.ceil( this.x );\n\t\tthis.y = Math.ceil( this.y );\n\t\tthis.z = Math.ceil( this.z );\n\t\tthis.w = Math.ceil( this.w );\n\n\t\treturn this;\n\n\t},\n\n\tround: function () {\n\n\t\tthis.x = Math.round( this.x );\n\t\tthis.y = Math.round( this.y );\n\t\tthis.z = Math.round( this.z );\n\t\tthis.w = Math.round( this.w );\n\n\t\treturn this;\n\n\t},\n\n\troundToZero: function () {\n\n\t\tthis.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );\n\t\tthis.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );\n\t\tthis.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );\n\t\tthis.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );\n\n\t\treturn this;\n\n\t},\n\n\tnegate: function () {\n\n\t\tthis.x = - this.x;\n\t\tthis.y = - this.y;\n\t\tthis.z = - this.z;\n\t\tthis.w = - this.w;\n\n\t\treturn this;\n\n\t},\n\n\tdot: function ( v ) {\n\n\t\treturn this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;\n\n\t},\n\n\tlengthSq: function () {\n\n\t\treturn this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;\n\n\t},\n\n\tlength: function () {\n\n\t\treturn Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );\n\n\t},\n\n\tlengthManhattan: function () {\n\n\t\treturn Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );\n\n\t},\n\n\tnormalize: function () {\n\n\t\treturn this.divideScalar( this.length() );\n\n\t},\n\n\tsetLength: function ( length ) {\n\n\t\treturn this.multiplyScalar( length / this.length() );\n\n\t},\n\n\tlerp: function ( v, alpha ) {\n\n\t\tthis.x += ( v.x - this.x ) * alpha;\n\t\tthis.y += ( v.y - this.y ) * alpha;\n\t\tthis.z += ( v.z - this.z ) * alpha;\n\t\tthis.w += ( v.w - this.w ) * alpha;\n\n\t\treturn this;\n\n\t},\n\n\tlerpVectors: function ( v1, v2, alpha ) {\n\n\t\treturn this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );\n\n\t},\n\n\tequals: function ( v ) {\n\n\t\treturn ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );\n\n\t},\n\n\tfromArray: function ( array, offset ) {\n\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tthis.x = array[ offset ];\n\t\tthis.y = array[ offset + 1 ];\n\t\tthis.z = array[ offset + 2 ];\n\t\tthis.w = array[ offset + 3 ];\n\n\t\treturn this;\n\n\t},\n\n\ttoArray: function ( array, offset ) {\n\n\t\tif ( array === undefined ) array = [];\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tarray[ offset ] = this.x;\n\t\tarray[ offset + 1 ] = this.y;\n\t\tarray[ offset + 2 ] = this.z;\n\t\tarray[ offset + 3 ] = this.w;\n\n\t\treturn array;\n\n\t},\n\n\tfromBufferAttribute: function ( attribute, index, offset ) {\n\n\t\tif ( offset !== undefined ) {\n\n\t\t\tconsole.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' );\n\n\t\t}\n\n\t\tthis.x = attribute.getX( index );\n\t\tthis.y = attribute.getY( index );\n\t\tthis.z = attribute.getZ( index );\n\t\tthis.w = attribute.getW( index );\n\n\t\treturn this;\n\n\t}\n\n};\n\n/**\n * @author szimek / https://github.com/szimek/\n * @author alteredq / http://alteredqualia.com/\n * @author Marius Kintel / https://github.com/kintel\n */\n\n/*\n In options, we can specify:\n * Texture parameters for an auto-generated target texture\n * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers\n*/\nfunction WebGLRenderTarget( width, height, options ) {\n\n\tthis.uuid = _Math.generateUUID();\n\n\tthis.width = width;\n\tthis.height = height;\n\n\tthis.scissor = new Vector4( 0, 0, width, height );\n\tthis.scissorTest = false;\n\n\tthis.viewport = new Vector4( 0, 0, width, height );\n\n\toptions = options || {};\n\n\tif ( options.minFilter === undefined ) options.minFilter = LinearFilter;\n\n\tthis.texture = new Texture( undefined, undefined, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );\n\n\tthis.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;\n\tthis.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true;\n\tthis.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null;\n\n}\n\nWebGLRenderTarget.prototype = {\n\n\tconstructor: WebGLRenderTarget,\n\n\tisWebGLRenderTarget: true,\n\n\tsetSize: function ( width, height ) {\n\n\t\tif ( this.width !== width || this.height !== height ) {\n\n\t\t\tthis.width = width;\n\t\t\tthis.height = height;\n\n\t\t\tthis.dispose();\n\n\t\t}\n\n\t\tthis.viewport.set( 0, 0, width, height );\n\t\tthis.scissor.set( 0, 0, width, height );\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor().copy( this );\n\n\t},\n\n\tcopy: function ( source ) {\n\n\t\tthis.width = source.width;\n\t\tthis.height = source.height;\n\n\t\tthis.viewport.copy( source.viewport );\n\n\t\tthis.texture = source.texture.clone();\n\n\t\tthis.depthBuffer = source.depthBuffer;\n\t\tthis.stencilBuffer = source.stencilBuffer;\n\t\tthis.depthTexture = source.depthTexture;\n\n\t\treturn this;\n\n\t},\n\n\tdispose: function () {\n\n\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t}\n\n};\n\nObject.assign( WebGLRenderTarget.prototype, EventDispatcher.prototype );\n\n/**\n * @author alteredq / http://alteredqualia.com\n */\n\nfunction WebGLRenderTargetCube( width, height, options ) {\n\n\tWebGLRenderTarget.call( this, width, height, options );\n\n\tthis.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5\n\tthis.activeMipMapLevel = 0;\n\n}\n\nWebGLRenderTargetCube.prototype = Object.create( WebGLRenderTarget.prototype );\nWebGLRenderTargetCube.prototype.constructor = WebGLRenderTargetCube;\n\nWebGLRenderTargetCube.prototype.isWebGLRenderTargetCube = true;\n\n/**\n * @author mikael emtinger / http://gomo.se/\n * @author alteredq / http://alteredqualia.com/\n * @author WestLangley / http://github.com/WestLangley\n * @author bhouston / http://clara.io\n */\n\nfunction Quaternion( x, y, z, w ) {\n\n\tthis._x = x || 0;\n\tthis._y = y || 0;\n\tthis._z = z || 0;\n\tthis._w = ( w !== undefined ) ? w : 1;\n\n}\n\nQuaternion.prototype = {\n\n\tconstructor: Quaternion,\n\n\tget x () {\n\n\t\treturn this._x;\n\n\t},\n\n\tset x ( value ) {\n\n\t\tthis._x = value;\n\t\tthis.onChangeCallback();\n\n\t},\n\n\tget y () {\n\n\t\treturn this._y;\n\n\t},\n\n\tset y ( value ) {\n\n\t\tthis._y = value;\n\t\tthis.onChangeCallback();\n\n\t},\n\n\tget z () {\n\n\t\treturn this._z;\n\n\t},\n\n\tset z ( value ) {\n\n\t\tthis._z = value;\n\t\tthis.onChangeCallback();\n\n\t},\n\n\tget w () {\n\n\t\treturn this._w;\n\n\t},\n\n\tset w ( value ) {\n\n\t\tthis._w = value;\n\t\tthis.onChangeCallback();\n\n\t},\n\n\tset: function ( x, y, z, w ) {\n\n\t\tthis._x = x;\n\t\tthis._y = y;\n\t\tthis._z = z;\n\t\tthis._w = w;\n\n\t\tthis.onChangeCallback();\n\n\t\treturn this;\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor( this._x, this._y, this._z, this._w );\n\n\t},\n\n\tcopy: function ( quaternion ) {\n\n\t\tthis._x = quaternion.x;\n\t\tthis._y = quaternion.y;\n\t\tthis._z = quaternion.z;\n\t\tthis._w = quaternion.w;\n\n\t\tthis.onChangeCallback();\n\n\t\treturn this;\n\n\t},\n\n\tsetFromEuler: function ( euler, update ) {\n\n\t\tif ( (euler && euler.isEuler) === false ) {\n\n\t\t\tthrow new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' );\n\n\t\t}\n\n\t\t// http://www.mathworks.com/matlabcentral/fileexchange/\n\t\t// \t20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/\n\t\t//\tcontent/SpinCalc.m\n\n\t\tvar c1 = Math.cos( euler._x / 2 );\n\t\tvar c2 = Math.cos( euler._y / 2 );\n\t\tvar c3 = Math.cos( euler._z / 2 );\n\t\tvar s1 = Math.sin( euler._x / 2 );\n\t\tvar s2 = Math.sin( euler._y / 2 );\n\t\tvar s3 = Math.sin( euler._z / 2 );\n\n\t\tvar order = euler.order;\n\n\t\tif ( order === 'XYZ' ) {\n\n\t\t\tthis._x = s1 * c2 * c3 + c1 * s2 * s3;\n\t\t\tthis._y = c1 * s2 * c3 - s1 * c2 * s3;\n\t\t\tthis._z = c1 * c2 * s3 + s1 * s2 * c3;\n\t\t\tthis._w = c1 * c2 * c3 - s1 * s2 * s3;\n\n\t\t} else if ( order === 'YXZ' ) {\n\n\t\t\tthis._x = s1 * c2 * c3 + c1 * s2 * s3;\n\t\t\tthis._y = c1 * s2 * c3 - s1 * c2 * s3;\n\t\t\tthis._z = c1 * c2 * s3 - s1 * s2 * c3;\n\t\t\tthis._w = c1 * c2 * c3 + s1 * s2 * s3;\n\n\t\t} else if ( order === 'ZXY' ) {\n\n\t\t\tthis._x = s1 * c2 * c3 - c1 * s2 * s3;\n\t\t\tthis._y = c1 * s2 * c3 + s1 * c2 * s3;\n\t\t\tthis._z = c1 * c2 * s3 + s1 * s2 * c3;\n\t\t\tthis._w = c1 * c2 * c3 - s1 * s2 * s3;\n\n\t\t} else if ( order === 'ZYX' ) {\n\n\t\t\tthis._x = s1 * c2 * c3 - c1 * s2 * s3;\n\t\t\tthis._y = c1 * s2 * c3 + s1 * c2 * s3;\n\t\t\tthis._z = c1 * c2 * s3 - s1 * s2 * c3;\n\t\t\tthis._w = c1 * c2 * c3 + s1 * s2 * s3;\n\n\t\t} else if ( order === 'YZX' ) {\n\n\t\t\tthis._x = s1 * c2 * c3 + c1 * s2 * s3;\n\t\t\tthis._y = c1 * s2 * c3 + s1 * c2 * s3;\n\t\t\tthis._z = c1 * c2 * s3 - s1 * s2 * c3;\n\t\t\tthis._w = c1 * c2 * c3 - s1 * s2 * s3;\n\n\t\t} else if ( order === 'XZY' ) {\n\n\t\t\tthis._x = s1 * c2 * c3 - c1 * s2 * s3;\n\t\t\tthis._y = c1 * s2 * c3 - s1 * c2 * s3;\n\t\t\tthis._z = c1 * c2 * s3 + s1 * s2 * c3;\n\t\t\tthis._w = c1 * c2 * c3 + s1 * s2 * s3;\n\n\t\t}\n\n\t\tif ( update !== false ) this.onChangeCallback();\n\n\t\treturn this;\n\n\t},\n\n\tsetFromAxisAngle: function ( axis, angle ) {\n\n\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm\n\n\t\t// assumes axis is normalized\n\n\t\tvar halfAngle = angle / 2, s = Math.sin( halfAngle );\n\n\t\tthis._x = axis.x * s;\n\t\tthis._y = axis.y * s;\n\t\tthis._z = axis.z * s;\n\t\tthis._w = Math.cos( halfAngle );\n\n\t\tthis.onChangeCallback();\n\n\t\treturn this;\n\n\t},\n\n\tsetFromRotationMatrix: function ( m ) {\n\n\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm\n\n\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\n\n\t\tvar te = m.elements,\n\n\t\t\tm11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],\n\t\t\tm21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],\n\t\t\tm31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],\n\n\t\t\ttrace = m11 + m22 + m33,\n\t\t\ts;\n\n\t\tif ( trace > 0 ) {\n\n\t\t\ts = 0.5 / Math.sqrt( trace + 1.0 );\n\n\t\t\tthis._w = 0.25 / s;\n\t\t\tthis._x = ( m32 - m23 ) * s;\n\t\t\tthis._y = ( m13 - m31 ) * s;\n\t\t\tthis._z = ( m21 - m12 ) * s;\n\n\t\t} else if ( m11 > m22 && m11 > m33 ) {\n\n\t\t\ts = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );\n\n\t\t\tthis._w = ( m32 - m23 ) / s;\n\t\t\tthis._x = 0.25 * s;\n\t\t\tthis._y = ( m12 + m21 ) / s;\n\t\t\tthis._z = ( m13 + m31 ) / s;\n\n\t\t} else if ( m22 > m33 ) {\n\n\t\t\ts = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );\n\n\t\t\tthis._w = ( m13 - m31 ) / s;\n\t\t\tthis._x = ( m12 + m21 ) / s;\n\t\t\tthis._y = 0.25 * s;\n\t\t\tthis._z = ( m23 + m32 ) / s;\n\n\t\t} else {\n\n\t\t\ts = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );\n\n\t\t\tthis._w = ( m21 - m12 ) / s;\n\t\t\tthis._x = ( m13 + m31 ) / s;\n\t\t\tthis._y = ( m23 + m32 ) / s;\n\t\t\tthis._z = 0.25 * s;\n\n\t\t}\n\n\t\tthis.onChangeCallback();\n\n\t\treturn this;\n\n\t},\n\n\tsetFromUnitVectors: function () {\n\n\t\t// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final\n\n\t\t// assumes direction vectors vFrom and vTo are normalized\n\n\t\tvar v1, r;\n\n\t\tvar EPS = 0.000001;\n\n\t\treturn function setFromUnitVectors( vFrom, vTo ) {\n\n\t\t\tif ( v1 === undefined ) v1 = new Vector3();\n\n\t\t\tr = vFrom.dot( vTo ) + 1;\n\n\t\t\tif ( r < EPS ) {\n\n\t\t\t\tr = 0;\n\n\t\t\t\tif ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {\n\n\t\t\t\t\tv1.set( - vFrom.y, vFrom.x, 0 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tv1.set( 0, - vFrom.z, vFrom.y );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tv1.crossVectors( vFrom, vTo );\n\n\t\t\t}\n\n\t\t\tthis._x = v1.x;\n\t\t\tthis._y = v1.y;\n\t\t\tthis._z = v1.z;\n\t\t\tthis._w = r;\n\n\t\t\treturn this.normalize();\n\n\t\t};\n\n\t}(),\n\n\tinverse: function () {\n\n\t\treturn this.conjugate().normalize();\n\n\t},\n\n\tconjugate: function () {\n\n\t\tthis._x *= - 1;\n\t\tthis._y *= - 1;\n\t\tthis._z *= - 1;\n\n\t\tthis.onChangeCallback();\n\n\t\treturn this;\n\n\t},\n\n\tdot: function ( v ) {\n\n\t\treturn this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;\n\n\t},\n\n\tlengthSq: function () {\n\n\t\treturn this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;\n\n\t},\n\n\tlength: function () {\n\n\t\treturn Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );\n\n\t},\n\n\tnormalize: function () {\n\n\t\tvar l = this.length();\n\n\t\tif ( l === 0 ) {\n\n\t\t\tthis._x = 0;\n\t\t\tthis._y = 0;\n\t\t\tthis._z = 0;\n\t\t\tthis._w = 1;\n\n\t\t} else {\n\n\t\t\tl = 1 / l;\n\n\t\t\tthis._x = this._x * l;\n\t\t\tthis._y = this._y * l;\n\t\t\tthis._z = this._z * l;\n\t\t\tthis._w = this._w * l;\n\n\t\t}\n\n\t\tthis.onChangeCallback();\n\n\t\treturn this;\n\n\t},\n\n\tmultiply: function ( q, p ) {\n\n\t\tif ( p !== undefined ) {\n\n\t\t\tconsole.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );\n\t\t\treturn this.multiplyQuaternions( q, p );\n\n\t\t}\n\n\t\treturn this.multiplyQuaternions( this, q );\n\n\t},\n\n\tpremultiply: function ( q ) {\n\n\t\treturn this.multiplyQuaternions( q, this );\n\n\t},\n\n\tmultiplyQuaternions: function ( a, b ) {\n\n\t\t// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm\n\n\t\tvar qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;\n\t\tvar qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;\n\n\t\tthis._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;\n\t\tthis._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;\n\t\tthis._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;\n\t\tthis._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;\n\n\t\tthis.onChangeCallback();\n\n\t\treturn this;\n\n\t},\n\n\tslerp: function ( qb, t ) {\n\n\t\tif ( t === 0 ) return this;\n\t\tif ( t === 1 ) return this.copy( qb );\n\n\t\tvar x = this._x, y = this._y, z = this._z, w = this._w;\n\n\t\t// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/\n\n\t\tvar cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;\n\n\t\tif ( cosHalfTheta < 0 ) {\n\n\t\t\tthis._w = - qb._w;\n\t\t\tthis._x = - qb._x;\n\t\t\tthis._y = - qb._y;\n\t\t\tthis._z = - qb._z;\n\n\t\t\tcosHalfTheta = - cosHalfTheta;\n\n\t\t} else {\n\n\t\t\tthis.copy( qb );\n\n\t\t}\n\n\t\tif ( cosHalfTheta >= 1.0 ) {\n\n\t\t\tthis._w = w;\n\t\t\tthis._x = x;\n\t\t\tthis._y = y;\n\t\t\tthis._z = z;\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tvar sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );\n\n\t\tif ( Math.abs( sinHalfTheta ) < 0.001 ) {\n\n\t\t\tthis._w = 0.5 * ( w + this._w );\n\t\t\tthis._x = 0.5 * ( x + this._x );\n\t\t\tthis._y = 0.5 * ( y + this._y );\n\t\t\tthis._z = 0.5 * ( z + this._z );\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tvar halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );\n\t\tvar ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,\n\t\tratioB = Math.sin( t * halfTheta ) / sinHalfTheta;\n\n\t\tthis._w = ( w * ratioA + this._w * ratioB );\n\t\tthis._x = ( x * ratioA + this._x * ratioB );\n\t\tthis._y = ( y * ratioA + this._y * ratioB );\n\t\tthis._z = ( z * ratioA + this._z * ratioB );\n\n\t\tthis.onChangeCallback();\n\n\t\treturn this;\n\n\t},\n\n\tequals: function ( quaternion ) {\n\n\t\treturn ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );\n\n\t},\n\n\tfromArray: function ( array, offset ) {\n\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tthis._x = array[ offset ];\n\t\tthis._y = array[ offset + 1 ];\n\t\tthis._z = array[ offset + 2 ];\n\t\tthis._w = array[ offset + 3 ];\n\n\t\tthis.onChangeCallback();\n\n\t\treturn this;\n\n\t},\n\n\ttoArray: function ( array, offset ) {\n\n\t\tif ( array === undefined ) array = [];\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tarray[ offset ] = this._x;\n\t\tarray[ offset + 1 ] = this._y;\n\t\tarray[ offset + 2 ] = this._z;\n\t\tarray[ offset + 3 ] = this._w;\n\n\t\treturn array;\n\n\t},\n\n\tonChange: function ( callback ) {\n\n\t\tthis.onChangeCallback = callback;\n\n\t\treturn this;\n\n\t},\n\n\tonChangeCallback: function () {}\n\n};\n\nObject.assign( Quaternion, {\n\n\tslerp: function( qa, qb, qm, t ) {\n\n\t\treturn qm.copy( qa ).slerp( qb, t );\n\n\t},\n\n\tslerpFlat: function(\n\t\t\tdst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {\n\n\t\t// fuzz-free, array-based Quaternion SLERP operation\n\n\t\tvar x0 = src0[ srcOffset0 + 0 ],\n\t\t\ty0 = src0[ srcOffset0 + 1 ],\n\t\t\tz0 = src0[ srcOffset0 + 2 ],\n\t\t\tw0 = src0[ srcOffset0 + 3 ],\n\n\t\t\tx1 = src1[ srcOffset1 + 0 ],\n\t\t\ty1 = src1[ srcOffset1 + 1 ],\n\t\t\tz1 = src1[ srcOffset1 + 2 ],\n\t\t\tw1 = src1[ srcOffset1 + 3 ];\n\n\t\tif ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {\n\n\t\t\tvar s = 1 - t,\n\n\t\t\t\tcos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,\n\n\t\t\t\tdir = ( cos >= 0 ? 1 : - 1 ),\n\t\t\t\tsqrSin = 1 - cos * cos;\n\n\t\t\t// Skip the Slerp for tiny steps to avoid numeric problems:\n\t\t\tif ( sqrSin > Number.EPSILON ) {\n\n\t\t\t\tvar sin = Math.sqrt( sqrSin ),\n\t\t\t\t\tlen = Math.atan2( sin, cos * dir );\n\n\t\t\t\ts = Math.sin( s * len ) / sin;\n\t\t\t\tt = Math.sin( t * len ) / sin;\n\n\t\t\t}\n\n\t\t\tvar tDir = t * dir;\n\n\t\t\tx0 = x0 * s + x1 * tDir;\n\t\t\ty0 = y0 * s + y1 * tDir;\n\t\t\tz0 = z0 * s + z1 * tDir;\n\t\t\tw0 = w0 * s + w1 * tDir;\n\n\t\t\t// Normalize in case we just did a lerp:\n\t\t\tif ( s === 1 - t ) {\n\n\t\t\t\tvar f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );\n\n\t\t\t\tx0 *= f;\n\t\t\t\ty0 *= f;\n\t\t\t\tz0 *= f;\n\t\t\t\tw0 *= f;\n\n\t\t\t}\n\n\t\t}\n\n\t\tdst[ dstOffset ] = x0;\n\t\tdst[ dstOffset + 1 ] = y0;\n\t\tdst[ dstOffset + 2 ] = z0;\n\t\tdst[ dstOffset + 3 ] = w0;\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author *kile / http://kile.stravaganza.org/\n * @author philogb / http://blog.thejit.org/\n * @author mikael emtinger / http://gomo.se/\n * @author egraether / http://egraether.com/\n * @author WestLangley / http://github.com/WestLangley\n */\n\nfunction Vector3( x, y, z ) {\n\n\tthis.x = x || 0;\n\tthis.y = y || 0;\n\tthis.z = z || 0;\n\n}\n\nVector3.prototype = {\n\n\tconstructor: Vector3,\n\n\tisVector3: true,\n\n\tset: function ( x, y, z ) {\n\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.z = z;\n\n\t\treturn this;\n\n\t},\n\n\tsetScalar: function ( scalar ) {\n\n\t\tthis.x = scalar;\n\t\tthis.y = scalar;\n\t\tthis.z = scalar;\n\n\t\treturn this;\n\n\t},\n\n\tsetX: function ( x ) {\n\n\t\tthis.x = x;\n\n\t\treturn this;\n\n\t},\n\n\tsetY: function ( y ) {\n\n\t\tthis.y = y;\n\n\t\treturn this;\n\n\t},\n\n\tsetZ: function ( z ) {\n\n\t\tthis.z = z;\n\n\t\treturn this;\n\n\t},\n\n\tsetComponent: function ( index, value ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: this.x = value; break;\n\t\t\tcase 1: this.y = value; break;\n\t\t\tcase 2: this.z = value; break;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tgetComponent: function ( index ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: return this.x;\n\t\t\tcase 1: return this.y;\n\t\t\tcase 2: return this.z;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor( this.x, this.y, this.z );\n\n\t},\n\n\tcopy: function ( v ) {\n\n\t\tthis.x = v.x;\n\t\tthis.y = v.y;\n\t\tthis.z = v.z;\n\n\t\treturn this;\n\n\t},\n\n\tadd: function ( v, w ) {\n\n\t\tif ( w !== undefined ) {\n\n\t\t\tconsole.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );\n\t\t\treturn this.addVectors( v, w );\n\n\t\t}\n\n\t\tthis.x += v.x;\n\t\tthis.y += v.y;\n\t\tthis.z += v.z;\n\n\t\treturn this;\n\n\t},\n\n\taddScalar: function ( s ) {\n\n\t\tthis.x += s;\n\t\tthis.y += s;\n\t\tthis.z += s;\n\n\t\treturn this;\n\n\t},\n\n\taddVectors: function ( a, b ) {\n\n\t\tthis.x = a.x + b.x;\n\t\tthis.y = a.y + b.y;\n\t\tthis.z = a.z + b.z;\n\n\t\treturn this;\n\n\t},\n\n\taddScaledVector: function ( v, s ) {\n\n\t\tthis.x += v.x * s;\n\t\tthis.y += v.y * s;\n\t\tthis.z += v.z * s;\n\n\t\treturn this;\n\n\t},\n\n\tsub: function ( v, w ) {\n\n\t\tif ( w !== undefined ) {\n\n\t\t\tconsole.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );\n\t\t\treturn this.subVectors( v, w );\n\n\t\t}\n\n\t\tthis.x -= v.x;\n\t\tthis.y -= v.y;\n\t\tthis.z -= v.z;\n\n\t\treturn this;\n\n\t},\n\n\tsubScalar: function ( s ) {\n\n\t\tthis.x -= s;\n\t\tthis.y -= s;\n\t\tthis.z -= s;\n\n\t\treturn this;\n\n\t},\n\n\tsubVectors: function ( a, b ) {\n\n\t\tthis.x = a.x - b.x;\n\t\tthis.y = a.y - b.y;\n\t\tthis.z = a.z - b.z;\n\n\t\treturn this;\n\n\t},\n\n\tmultiply: function ( v, w ) {\n\n\t\tif ( w !== undefined ) {\n\n\t\t\tconsole.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );\n\t\t\treturn this.multiplyVectors( v, w );\n\n\t\t}\n\n\t\tthis.x *= v.x;\n\t\tthis.y *= v.y;\n\t\tthis.z *= v.z;\n\n\t\treturn this;\n\n\t},\n\n\tmultiplyScalar: function ( scalar ) {\n\n\t\tif ( isFinite( scalar ) ) {\n\n\t\t\tthis.x *= scalar;\n\t\t\tthis.y *= scalar;\n\t\t\tthis.z *= scalar;\n\n\t\t} else {\n\n\t\t\tthis.x = 0;\n\t\t\tthis.y = 0;\n\t\t\tthis.z = 0;\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tmultiplyVectors: function ( a, b ) {\n\n\t\tthis.x = a.x * b.x;\n\t\tthis.y = a.y * b.y;\n\t\tthis.z = a.z * b.z;\n\n\t\treturn this;\n\n\t},\n\n\tapplyEuler: function () {\n\n\t\tvar quaternion;\n\n\t\treturn function applyEuler( euler ) {\n\n\t\t\tif ( (euler && euler.isEuler) === false ) {\n\n\t\t\t\tconsole.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' );\n\n\t\t\t}\n\n\t\t\tif ( quaternion === undefined ) quaternion = new Quaternion();\n\n\t\t\treturn this.applyQuaternion( quaternion.setFromEuler( euler ) );\n\n\t\t};\n\n\t}(),\n\n\tapplyAxisAngle: function () {\n\n\t\tvar quaternion;\n\n\t\treturn function applyAxisAngle( axis, angle ) {\n\n\t\t\tif ( quaternion === undefined ) quaternion = new Quaternion();\n\n\t\t\treturn this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) );\n\n\t\t};\n\n\t}(),\n\n\tapplyMatrix3: function ( m ) {\n\n\t\tvar x = this.x, y = this.y, z = this.z;\n\t\tvar e = m.elements;\n\n\t\tthis.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;\n\t\tthis.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;\n\t\tthis.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;\n\n\t\treturn this;\n\n\t},\n\n\tapplyMatrix4: function ( m ) {\n\n\t\tvar x = this.x, y = this.y, z = this.z;\n\t\tvar e = m.elements;\n\n\t\tthis.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ];\n\t\tthis.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ];\n\t\tthis.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ];\n\t\tvar w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ];\n\n\t\treturn this.divideScalar( w );\n\n\t},\n\n\tapplyQuaternion: function ( q ) {\n\n\t\tvar x = this.x, y = this.y, z = this.z;\n\t\tvar qx = q.x, qy = q.y, qz = q.z, qw = q.w;\n\n\t\t// calculate quat * vector\n\n\t\tvar ix = qw * x + qy * z - qz * y;\n\t\tvar iy = qw * y + qz * x - qx * z;\n\t\tvar iz = qw * z + qx * y - qy * x;\n\t\tvar iw = - qx * x - qy * y - qz * z;\n\n\t\t// calculate result * inverse quat\n\n\t\tthis.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;\n\t\tthis.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;\n\t\tthis.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;\n\n\t\treturn this;\n\n\t},\n\n\tproject: function () {\n\n\t\tvar matrix;\n\n\t\treturn function project( camera ) {\n\n\t\t\tif ( matrix === undefined ) matrix = new Matrix4();\n\n\t\t\tmatrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );\n\t\t\treturn this.applyMatrix4( matrix );\n\n\t\t};\n\n\t}(),\n\n\tunproject: function () {\n\n\t\tvar matrix;\n\n\t\treturn function unproject( camera ) {\n\n\t\t\tif ( matrix === undefined ) matrix = new Matrix4();\n\n\t\t\tmatrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );\n\t\t\treturn this.applyMatrix4( matrix );\n\n\t\t};\n\n\t}(),\n\n\ttransformDirection: function ( m ) {\n\n\t\t// input: THREE.Matrix4 affine matrix\n\t\t// vector interpreted as a direction\n\n\t\tvar x = this.x, y = this.y, z = this.z;\n\t\tvar e = m.elements;\n\n\t\tthis.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;\n\t\tthis.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;\n\t\tthis.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;\n\n\t\treturn this.normalize();\n\n\t},\n\n\tdivide: function ( v ) {\n\n\t\tthis.x /= v.x;\n\t\tthis.y /= v.y;\n\t\tthis.z /= v.z;\n\n\t\treturn this;\n\n\t},\n\n\tdivideScalar: function ( scalar ) {\n\n\t\treturn this.multiplyScalar( 1 / scalar );\n\n\t},\n\n\tmin: function ( v ) {\n\n\t\tthis.x = Math.min( this.x, v.x );\n\t\tthis.y = Math.min( this.y, v.y );\n\t\tthis.z = Math.min( this.z, v.z );\n\n\t\treturn this;\n\n\t},\n\n\tmax: function ( v ) {\n\n\t\tthis.x = Math.max( this.x, v.x );\n\t\tthis.y = Math.max( this.y, v.y );\n\t\tthis.z = Math.max( this.z, v.z );\n\n\t\treturn this;\n\n\t},\n\n\tclamp: function ( min, max ) {\n\n\t\t// This function assumes min < max, if this assumption isn't true it will not operate correctly\n\n\t\tthis.x = Math.max( min.x, Math.min( max.x, this.x ) );\n\t\tthis.y = Math.max( min.y, Math.min( max.y, this.y ) );\n\t\tthis.z = Math.max( min.z, Math.min( max.z, this.z ) );\n\n\t\treturn this;\n\n\t},\n\n\tclampScalar: function () {\n\n\t\tvar min, max;\n\n\t\treturn function clampScalar( minVal, maxVal ) {\n\n\t\t\tif ( min === undefined ) {\n\n\t\t\t\tmin = new Vector3();\n\t\t\t\tmax = new Vector3();\n\n\t\t\t}\n\n\t\t\tmin.set( minVal, minVal, minVal );\n\t\t\tmax.set( maxVal, maxVal, maxVal );\n\n\t\t\treturn this.clamp( min, max );\n\n\t\t};\n\n\t}(),\n\n\tclampLength: function ( min, max ) {\n\n\t\tvar length = this.length();\n\n\t\treturn this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length );\n\n\t},\n\n\tfloor: function () {\n\n\t\tthis.x = Math.floor( this.x );\n\t\tthis.y = Math.floor( this.y );\n\t\tthis.z = Math.floor( this.z );\n\n\t\treturn this;\n\n\t},\n\n\tceil: function () {\n\n\t\tthis.x = Math.ceil( this.x );\n\t\tthis.y = Math.ceil( this.y );\n\t\tthis.z = Math.ceil( this.z );\n\n\t\treturn this;\n\n\t},\n\n\tround: function () {\n\n\t\tthis.x = Math.round( this.x );\n\t\tthis.y = Math.round( this.y );\n\t\tthis.z = Math.round( this.z );\n\n\t\treturn this;\n\n\t},\n\n\troundToZero: function () {\n\n\t\tthis.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );\n\t\tthis.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );\n\t\tthis.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );\n\n\t\treturn this;\n\n\t},\n\n\tnegate: function () {\n\n\t\tthis.x = - this.x;\n\t\tthis.y = - this.y;\n\t\tthis.z = - this.z;\n\n\t\treturn this;\n\n\t},\n\n\tdot: function ( v ) {\n\n\t\treturn this.x * v.x + this.y * v.y + this.z * v.z;\n\n\t},\n\n\tlengthSq: function () {\n\n\t\treturn this.x * this.x + this.y * this.y + this.z * this.z;\n\n\t},\n\n\tlength: function () {\n\n\t\treturn Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );\n\n\t},\n\n\tlengthManhattan: function () {\n\n\t\treturn Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );\n\n\t},\n\n\tnormalize: function () {\n\n\t\treturn this.divideScalar( this.length() );\n\n\t},\n\n\tsetLength: function ( length ) {\n\n\t\treturn this.multiplyScalar( length / this.length() );\n\n\t},\n\n\tlerp: function ( v, alpha ) {\n\n\t\tthis.x += ( v.x - this.x ) * alpha;\n\t\tthis.y += ( v.y - this.y ) * alpha;\n\t\tthis.z += ( v.z - this.z ) * alpha;\n\n\t\treturn this;\n\n\t},\n\n\tlerpVectors: function ( v1, v2, alpha ) {\n\n\t\treturn this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );\n\n\t},\n\n\tcross: function ( v, w ) {\n\n\t\tif ( w !== undefined ) {\n\n\t\t\tconsole.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );\n\t\t\treturn this.crossVectors( v, w );\n\n\t\t}\n\n\t\tvar x = this.x, y = this.y, z = this.z;\n\n\t\tthis.x = y * v.z - z * v.y;\n\t\tthis.y = z * v.x - x * v.z;\n\t\tthis.z = x * v.y - y * v.x;\n\n\t\treturn this;\n\n\t},\n\n\tcrossVectors: function ( a, b ) {\n\n\t\tvar ax = a.x, ay = a.y, az = a.z;\n\t\tvar bx = b.x, by = b.y, bz = b.z;\n\n\t\tthis.x = ay * bz - az * by;\n\t\tthis.y = az * bx - ax * bz;\n\t\tthis.z = ax * by - ay * bx;\n\n\t\treturn this;\n\n\t},\n\n\tprojectOnVector: function ( vector ) {\n\n\t\tvar scalar = vector.dot( this ) / vector.lengthSq();\n\n\t\treturn this.copy( vector ).multiplyScalar( scalar );\n\n\t},\n\n\tprojectOnPlane: function () {\n\n\t\tvar v1;\n\n\t\treturn function projectOnPlane( planeNormal ) {\n\n\t\t\tif ( v1 === undefined ) v1 = new Vector3();\n\n\t\t\tv1.copy( this ).projectOnVector( planeNormal );\n\n\t\t\treturn this.sub( v1 );\n\n\t\t};\n\n\t}(),\n\n\treflect: function () {\n\n\t\t// reflect incident vector off plane orthogonal to normal\n\t\t// normal is assumed to have unit length\n\n\t\tvar v1;\n\n\t\treturn function reflect( normal ) {\n\n\t\t\tif ( v1 === undefined ) v1 = new Vector3();\n\n\t\t\treturn this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );\n\n\t\t};\n\n\t}(),\n\n\tangleTo: function ( v ) {\n\n\t\tvar theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) );\n\n\t\t// clamp, to handle numerical problems\n\n\t\treturn Math.acos( _Math.clamp( theta, - 1, 1 ) );\n\n\t},\n\n\tdistanceTo: function ( v ) {\n\n\t\treturn Math.sqrt( this.distanceToSquared( v ) );\n\n\t},\n\n\tdistanceToSquared: function ( v ) {\n\n\t\tvar dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;\n\n\t\treturn dx * dx + dy * dy + dz * dz;\n\n\t},\n\n\tdistanceToManhattan: function ( v ) {\n\n\t\treturn Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );\n\n\t},\n\n\tsetFromSpherical: function( s ) {\n\n\t\tvar sinPhiRadius = Math.sin( s.phi ) * s.radius;\n\n\t\tthis.x = sinPhiRadius * Math.sin( s.theta );\n\t\tthis.y = Math.cos( s.phi ) * s.radius;\n\t\tthis.z = sinPhiRadius * Math.cos( s.theta );\n\n\t\treturn this;\n\n\t},\n\n\tsetFromCylindrical: function( c ) {\n\n\t\tthis.x = c.radius * Math.sin( c.theta );\n\t\tthis.y = c.y;\n\t\tthis.z = c.radius * Math.cos( c.theta );\n\n\t\treturn this;\n\n\t},\n\n\tsetFromMatrixPosition: function ( m ) {\n\n\t\treturn this.setFromMatrixColumn( m, 3 );\n\n\t},\n\n\tsetFromMatrixScale: function ( m ) {\n\n\t\tvar sx = this.setFromMatrixColumn( m, 0 ).length();\n\t\tvar sy = this.setFromMatrixColumn( m, 1 ).length();\n\t\tvar sz = this.setFromMatrixColumn( m, 2 ).length();\n\n\t\tthis.x = sx;\n\t\tthis.y = sy;\n\t\tthis.z = sz;\n\n\t\treturn this;\n\n\t},\n\n\tsetFromMatrixColumn: function ( m, index ) {\n\n\t\tif ( typeof m === 'number' ) {\n\n\t\t\tconsole.warn( 'THREE.Vector3: setFromMatrixColumn now expects ( matrix, index ).' );\n\t\t\tvar temp = m;\n\t\t\tm = index;\n\t\t\tindex = temp;\n\n\t\t}\n\n\t\treturn this.fromArray( m.elements, index * 4 );\n\n\t},\n\n\tequals: function ( v ) {\n\n\t\treturn ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );\n\n\t},\n\n\tfromArray: function ( array, offset ) {\n\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tthis.x = array[ offset ];\n\t\tthis.y = array[ offset + 1 ];\n\t\tthis.z = array[ offset + 2 ];\n\n\t\treturn this;\n\n\t},\n\n\ttoArray: function ( array, offset ) {\n\n\t\tif ( array === undefined ) array = [];\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tarray[ offset ] = this.x;\n\t\tarray[ offset + 1 ] = this.y;\n\t\tarray[ offset + 2 ] = this.z;\n\n\t\treturn array;\n\n\t},\n\n\tfromBufferAttribute: function ( attribute, index, offset ) {\n\n\t\tif ( offset !== undefined ) {\n\n\t\t\tconsole.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' );\n\n\t\t}\n\n\t\tthis.x = attribute.getX( index );\n\t\tthis.y = attribute.getY( index );\n\t\tthis.z = attribute.getZ( index );\n\n\t\treturn this;\n\n\t}\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author supereggbert / http://www.paulbrunt.co.uk/\n * @author philogb / http://blog.thejit.org/\n * @author jordi_ros / http://plattsoft.com\n * @author D1plo1d / http://github.com/D1plo1d\n * @author alteredq / http://alteredqualia.com/\n * @author mikael emtinger / http://gomo.se/\n * @author timknip / http://www.floorplanner.com/\n * @author bhouston / http://clara.io\n * @author WestLangley / http://github.com/WestLangley\n */\n\nfunction Matrix4() {\n\n\tthis.elements = new Float32Array( [\n\n\t\t1, 0, 0, 0,\n\t\t0, 1, 0, 0,\n\t\t0, 0, 1, 0,\n\t\t0, 0, 0, 1\n\n\t] );\n\n\tif ( arguments.length > 0 ) {\n\n\t\tconsole.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );\n\n\t}\n\n}\n\nMatrix4.prototype = {\n\n\tconstructor: Matrix4,\n\n\tisMatrix4: true,\n\n\tset: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {\n\n\t\tvar te = this.elements;\n\n\t\tte[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;\n\t\tte[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;\n\t\tte[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;\n\t\tte[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;\n\n\t\treturn this;\n\n\t},\n\n\tidentity: function () {\n\n\t\tthis.set(\n\n\t\t\t1, 0, 0, 0,\n\t\t\t0, 1, 0, 0,\n\t\t\t0, 0, 1, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new Matrix4().fromArray( this.elements );\n\n\t},\n\n\tcopy: function ( m ) {\n\n\t\tthis.elements.set( m.elements );\n\n\t\treturn this;\n\n\t},\n\n\tcopyPosition: function ( m ) {\n\n\t\tvar te = this.elements;\n\t\tvar me = m.elements;\n\n\t\tte[ 12 ] = me[ 12 ];\n\t\tte[ 13 ] = me[ 13 ];\n\t\tte[ 14 ] = me[ 14 ];\n\n\t\treturn this;\n\n\t},\n\n\textractBasis: function ( xAxis, yAxis, zAxis ) {\n\n\t\txAxis.setFromMatrixColumn( this, 0 );\n\t\tyAxis.setFromMatrixColumn( this, 1 );\n\t\tzAxis.setFromMatrixColumn( this, 2 );\n\n\t\treturn this;\n\n\t},\n\n\tmakeBasis: function ( xAxis, yAxis, zAxis ) {\n\n\t\tthis.set(\n\t\t\txAxis.x, yAxis.x, zAxis.x, 0,\n\t\t\txAxis.y, yAxis.y, zAxis.y, 0,\n\t\t\txAxis.z, yAxis.z, zAxis.z, 0,\n\t\t\t0, 0, 0, 1\n\t\t);\n\n\t\treturn this;\n\n\t},\n\n\textractRotation: function () {\n\n\t\tvar v1;\n\n\t\treturn function extractRotation( m ) {\n\n\t\t\tif ( v1 === undefined ) v1 = new Vector3();\n\n\t\t\tvar te = this.elements;\n\t\t\tvar me = m.elements;\n\n\t\t\tvar scaleX = 1 / v1.setFromMatrixColumn( m, 0 ).length();\n\t\t\tvar scaleY = 1 / v1.setFromMatrixColumn( m, 1 ).length();\n\t\t\tvar scaleZ = 1 / v1.setFromMatrixColumn( m, 2 ).length();\n\n\t\t\tte[ 0 ] = me[ 0 ] * scaleX;\n\t\t\tte[ 1 ] = me[ 1 ] * scaleX;\n\t\t\tte[ 2 ] = me[ 2 ] * scaleX;\n\n\t\t\tte[ 4 ] = me[ 4 ] * scaleY;\n\t\t\tte[ 5 ] = me[ 5 ] * scaleY;\n\t\t\tte[ 6 ] = me[ 6 ] * scaleY;\n\n\t\t\tte[ 8 ] = me[ 8 ] * scaleZ;\n\t\t\tte[ 9 ] = me[ 9 ] * scaleZ;\n\t\t\tte[ 10 ] = me[ 10 ] * scaleZ;\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\tmakeRotationFromEuler: function ( euler ) {\n\n\t\tif ( (euler && euler.isEuler) === false ) {\n\n\t\t\tconsole.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );\n\n\t\t}\n\n\t\tvar te = this.elements;\n\n\t\tvar x = euler.x, y = euler.y, z = euler.z;\n\t\tvar a = Math.cos( x ), b = Math.sin( x );\n\t\tvar c = Math.cos( y ), d = Math.sin( y );\n\t\tvar e = Math.cos( z ), f = Math.sin( z );\n\n\t\tif ( euler.order === 'XYZ' ) {\n\n\t\t\tvar ae = a * e, af = a * f, be = b * e, bf = b * f;\n\n\t\t\tte[ 0 ] = c * e;\n\t\t\tte[ 4 ] = - c * f;\n\t\t\tte[ 8 ] = d;\n\n\t\t\tte[ 1 ] = af + be * d;\n\t\t\tte[ 5 ] = ae - bf * d;\n\t\t\tte[ 9 ] = - b * c;\n\n\t\t\tte[ 2 ] = bf - ae * d;\n\t\t\tte[ 6 ] = be + af * d;\n\t\t\tte[ 10 ] = a * c;\n\n\t\t} else if ( euler.order === 'YXZ' ) {\n\n\t\t\tvar ce = c * e, cf = c * f, de = d * e, df = d * f;\n\n\t\t\tte[ 0 ] = ce + df * b;\n\t\t\tte[ 4 ] = de * b - cf;\n\t\t\tte[ 8 ] = a * d;\n\n\t\t\tte[ 1 ] = a * f;\n\t\t\tte[ 5 ] = a * e;\n\t\t\tte[ 9 ] = - b;\n\n\t\t\tte[ 2 ] = cf * b - de;\n\t\t\tte[ 6 ] = df + ce * b;\n\t\t\tte[ 10 ] = a * c;\n\n\t\t} else if ( euler.order === 'ZXY' ) {\n\n\t\t\tvar ce = c * e, cf = c * f, de = d * e, df = d * f;\n\n\t\t\tte[ 0 ] = ce - df * b;\n\t\t\tte[ 4 ] = - a * f;\n\t\t\tte[ 8 ] = de + cf * b;\n\n\t\t\tte[ 1 ] = cf + de * b;\n\t\t\tte[ 5 ] = a * e;\n\t\t\tte[ 9 ] = df - ce * b;\n\n\t\t\tte[ 2 ] = - a * d;\n\t\t\tte[ 6 ] = b;\n\t\t\tte[ 10 ] = a * c;\n\n\t\t} else if ( euler.order === 'ZYX' ) {\n\n\t\t\tvar ae = a * e, af = a * f, be = b * e, bf = b * f;\n\n\t\t\tte[ 0 ] = c * e;\n\t\t\tte[ 4 ] = be * d - af;\n\t\t\tte[ 8 ] = ae * d + bf;\n\n\t\t\tte[ 1 ] = c * f;\n\t\t\tte[ 5 ] = bf * d + ae;\n\t\t\tte[ 9 ] = af * d - be;\n\n\t\t\tte[ 2 ] = - d;\n\t\t\tte[ 6 ] = b * c;\n\t\t\tte[ 10 ] = a * c;\n\n\t\t} else if ( euler.order === 'YZX' ) {\n\n\t\t\tvar ac = a * c, ad = a * d, bc = b * c, bd = b * d;\n\n\t\t\tte[ 0 ] = c * e;\n\t\t\tte[ 4 ] = bd - ac * f;\n\t\t\tte[ 8 ] = bc * f + ad;\n\n\t\t\tte[ 1 ] = f;\n\t\t\tte[ 5 ] = a * e;\n\t\t\tte[ 9 ] = - b * e;\n\n\t\t\tte[ 2 ] = - d * e;\n\t\t\tte[ 6 ] = ad * f + bc;\n\t\t\tte[ 10 ] = ac - bd * f;\n\n\t\t} else if ( euler.order === 'XZY' ) {\n\n\t\t\tvar ac = a * c, ad = a * d, bc = b * c, bd = b * d;\n\n\t\t\tte[ 0 ] = c * e;\n\t\t\tte[ 4 ] = - f;\n\t\t\tte[ 8 ] = d * e;\n\n\t\t\tte[ 1 ] = ac * f + bd;\n\t\t\tte[ 5 ] = a * e;\n\t\t\tte[ 9 ] = ad * f - bc;\n\n\t\t\tte[ 2 ] = bc * f - ad;\n\t\t\tte[ 6 ] = b * e;\n\t\t\tte[ 10 ] = bd * f + ac;\n\n\t\t}\n\n\t\t// last column\n\t\tte[ 3 ] = 0;\n\t\tte[ 7 ] = 0;\n\t\tte[ 11 ] = 0;\n\n\t\t// bottom row\n\t\tte[ 12 ] = 0;\n\t\tte[ 13 ] = 0;\n\t\tte[ 14 ] = 0;\n\t\tte[ 15 ] = 1;\n\n\t\treturn this;\n\n\t},\n\n\tmakeRotationFromQuaternion: function ( q ) {\n\n\t\tvar te = this.elements;\n\n\t\tvar x = q.x, y = q.y, z = q.z, w = q.w;\n\t\tvar x2 = x + x, y2 = y + y, z2 = z + z;\n\t\tvar xx = x * x2, xy = x * y2, xz = x * z2;\n\t\tvar yy = y * y2, yz = y * z2, zz = z * z2;\n\t\tvar wx = w * x2, wy = w * y2, wz = w * z2;\n\n\t\tte[ 0 ] = 1 - ( yy + zz );\n\t\tte[ 4 ] = xy - wz;\n\t\tte[ 8 ] = xz + wy;\n\n\t\tte[ 1 ] = xy + wz;\n\t\tte[ 5 ] = 1 - ( xx + zz );\n\t\tte[ 9 ] = yz - wx;\n\n\t\tte[ 2 ] = xz - wy;\n\t\tte[ 6 ] = yz + wx;\n\t\tte[ 10 ] = 1 - ( xx + yy );\n\n\t\t// last column\n\t\tte[ 3 ] = 0;\n\t\tte[ 7 ] = 0;\n\t\tte[ 11 ] = 0;\n\n\t\t// bottom row\n\t\tte[ 12 ] = 0;\n\t\tte[ 13 ] = 0;\n\t\tte[ 14 ] = 0;\n\t\tte[ 15 ] = 1;\n\n\t\treturn this;\n\n\t},\n\n\tlookAt: function () {\n\n\t\tvar x, y, z;\n\n\t\treturn function lookAt( eye, target, up ) {\n\n\t\t\tif ( x === undefined ) {\n\n\t\t\t\tx = new Vector3();\n\t\t\t\ty = new Vector3();\n\t\t\t\tz = new Vector3();\n\n\t\t\t}\n\n\t\t\tvar te = this.elements;\n\n\t\t\tz.subVectors( eye, target ).normalize();\n\n\t\t\tif ( z.lengthSq() === 0 ) {\n\n\t\t\t\tz.z = 1;\n\n\t\t\t}\n\n\t\t\tx.crossVectors( up, z ).normalize();\n\n\t\t\tif ( x.lengthSq() === 0 ) {\n\n\t\t\t\tz.z += 0.0001;\n\t\t\t\tx.crossVectors( up, z ).normalize();\n\n\t\t\t}\n\n\t\t\ty.crossVectors( z, x );\n\n\n\t\t\tte[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;\n\t\t\tte[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;\n\t\t\tte[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\tmultiply: function ( m, n ) {\n\n\t\tif ( n !== undefined ) {\n\n\t\t\tconsole.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );\n\t\t\treturn this.multiplyMatrices( m, n );\n\n\t\t}\n\n\t\treturn this.multiplyMatrices( this, m );\n\n\t},\n\n\tpremultiply: function ( m ) {\n\n\t\treturn this.multiplyMatrices( m, this );\n\n\t},\n\n\tmultiplyMatrices: function ( a, b ) {\n\n\t\tvar ae = a.elements;\n\t\tvar be = b.elements;\n\t\tvar te = this.elements;\n\n\t\tvar a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];\n\t\tvar a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];\n\t\tvar a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];\n\t\tvar a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];\n\n\t\tvar b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];\n\t\tvar b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];\n\t\tvar b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];\n\t\tvar b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];\n\n\t\tte[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;\n\t\tte[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;\n\t\tte[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;\n\t\tte[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;\n\n\t\tte[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;\n\t\tte[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;\n\t\tte[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;\n\t\tte[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;\n\n\t\tte[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;\n\t\tte[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;\n\t\tte[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;\n\t\tte[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;\n\n\t\tte[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;\n\t\tte[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;\n\t\tte[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;\n\t\tte[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;\n\n\t\treturn this;\n\n\t},\n\n\tmultiplyToArray: function ( a, b, r ) {\n\n\t\tvar te = this.elements;\n\n\t\tthis.multiplyMatrices( a, b );\n\n\t\tr[ 0 ] = te[ 0 ]; r[ 1 ] = te[ 1 ]; r[ 2 ] = te[ 2 ]; r[ 3 ] = te[ 3 ];\n\t\tr[ 4 ] = te[ 4 ]; r[ 5 ] = te[ 5 ]; r[ 6 ] = te[ 6 ]; r[ 7 ] = te[ 7 ];\n\t\tr[ 8 ] = te[ 8 ]; r[ 9 ] = te[ 9 ]; r[ 10 ] = te[ 10 ]; r[ 11 ] = te[ 11 ];\n\t\tr[ 12 ] = te[ 12 ]; r[ 13 ] = te[ 13 ]; r[ 14 ] = te[ 14 ]; r[ 15 ] = te[ 15 ];\n\n\t\treturn this;\n\n\t},\n\n\tmultiplyScalar: function ( s ) {\n\n\t\tvar te = this.elements;\n\n\t\tte[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;\n\t\tte[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;\n\t\tte[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;\n\t\tte[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;\n\n\t\treturn this;\n\n\t},\n\n\tapplyToBufferAttribute: function () {\n\n\t\tvar v1;\n\n\t\treturn function applyToBufferAttribute( attribute ) {\n\n\t\t\tif ( v1 === undefined ) v1 = new Vector3();\n\n\t\t\tfor ( var i = 0, l = attribute.count; i < l; i ++ ) {\n\n\t\t\t\tv1.x = attribute.getX( i );\n\t\t\t\tv1.y = attribute.getY( i );\n\t\t\t\tv1.z = attribute.getZ( i );\n\n\t\t\t\tv1.applyMatrix4( this );\n\n\t\t\t\tattribute.setXYZ( i, v1.x, v1.y, v1.z );\n\n\t\t\t}\n\n\t\t\treturn attribute;\n\n\t\t};\n\n\t}(),\n\n\tdeterminant: function () {\n\n\t\tvar te = this.elements;\n\n\t\tvar n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];\n\t\tvar n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];\n\t\tvar n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];\n\t\tvar n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];\n\n\t\t//TODO: make this more efficient\n\t\t//( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )\n\n\t\treturn (\n\t\t\tn41 * (\n\t\t\t\t+ n14 * n23 * n32\n\t\t\t\t - n13 * n24 * n32\n\t\t\t\t - n14 * n22 * n33\n\t\t\t\t + n12 * n24 * n33\n\t\t\t\t + n13 * n22 * n34\n\t\t\t\t - n12 * n23 * n34\n\t\t\t) +\n\t\t\tn42 * (\n\t\t\t\t+ n11 * n23 * n34\n\t\t\t\t - n11 * n24 * n33\n\t\t\t\t + n14 * n21 * n33\n\t\t\t\t - n13 * n21 * n34\n\t\t\t\t + n13 * n24 * n31\n\t\t\t\t - n14 * n23 * n31\n\t\t\t) +\n\t\t\tn43 * (\n\t\t\t\t+ n11 * n24 * n32\n\t\t\t\t - n11 * n22 * n34\n\t\t\t\t - n14 * n21 * n32\n\t\t\t\t + n12 * n21 * n34\n\t\t\t\t + n14 * n22 * n31\n\t\t\t\t - n12 * n24 * n31\n\t\t\t) +\n\t\t\tn44 * (\n\t\t\t\t- n13 * n22 * n31\n\t\t\t\t - n11 * n23 * n32\n\t\t\t\t + n11 * n22 * n33\n\t\t\t\t + n13 * n21 * n32\n\t\t\t\t - n12 * n21 * n33\n\t\t\t\t + n12 * n23 * n31\n\t\t\t)\n\n\t\t);\n\n\t},\n\n\ttranspose: function () {\n\n\t\tvar te = this.elements;\n\t\tvar tmp;\n\n\t\ttmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;\n\t\ttmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;\n\t\ttmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;\n\n\t\ttmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;\n\t\ttmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;\n\t\ttmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;\n\n\t\treturn this;\n\n\t},\n\n\tsetPosition: function ( v ) {\n\n\t\tvar te = this.elements;\n\n\t\tte[ 12 ] = v.x;\n\t\tte[ 13 ] = v.y;\n\t\tte[ 14 ] = v.z;\n\n\t\treturn this;\n\n\t},\n\n\tgetInverse: function ( m, throwOnDegenerate ) {\n\n\t\t// based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm\n\t\tvar te = this.elements,\n\t\t\tme = m.elements,\n\n\t\t\tn11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], n41 = me[ 3 ],\n\t\t\tn12 = me[ 4 ], n22 = me[ 5 ], n32 = me[ 6 ], n42 = me[ 7 ],\n\t\t\tn13 = me[ 8 ], n23 = me[ 9 ], n33 = me[ 10 ], n43 = me[ 11 ],\n\t\t\tn14 = me[ 12 ], n24 = me[ 13 ], n34 = me[ 14 ], n44 = me[ 15 ],\n\n\t\t\tt11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,\n\t\t\tt12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,\n\t\t\tt13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,\n\t\t\tt14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;\n\n\t\tvar det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;\n\n\t\tif ( det === 0 ) {\n\n\t\t\tvar msg = \"THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0\";\n\n\t\t\tif ( throwOnDegenerate === true ) {\n\n\t\t\t\tthrow new Error( msg );\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( msg );\n\n\t\t\t}\n\n\t\t\treturn this.identity();\n\n\t\t}\n\n\t\tvar detInv = 1 / det;\n\n\t\tte[ 0 ] = t11 * detInv;\n\t\tte[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;\n\t\tte[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;\n\t\tte[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;\n\n\t\tte[ 4 ] = t12 * detInv;\n\t\tte[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;\n\t\tte[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;\n\t\tte[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;\n\n\t\tte[ 8 ] = t13 * detInv;\n\t\tte[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;\n\t\tte[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;\n\t\tte[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;\n\n\t\tte[ 12 ] = t14 * detInv;\n\t\tte[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;\n\t\tte[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;\n\t\tte[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;\n\n\t\treturn this;\n\n\t},\n\n\tscale: function ( v ) {\n\n\t\tvar te = this.elements;\n\t\tvar x = v.x, y = v.y, z = v.z;\n\n\t\tte[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;\n\t\tte[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;\n\t\tte[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;\n\t\tte[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;\n\n\t\treturn this;\n\n\t},\n\n\tgetMaxScaleOnAxis: function () {\n\n\t\tvar te = this.elements;\n\n\t\tvar scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];\n\t\tvar scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];\n\t\tvar scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];\n\n\t\treturn Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );\n\n\t},\n\n\tmakeTranslation: function ( x, y, z ) {\n\n\t\tthis.set(\n\n\t\t\t1, 0, 0, x,\n\t\t\t0, 1, 0, y,\n\t\t\t0, 0, 1, z,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t},\n\n\tmakeRotationX: function ( theta ) {\n\n\t\tvar c = Math.cos( theta ), s = Math.sin( theta );\n\n\t\tthis.set(\n\n\t\t\t1, 0, 0, 0,\n\t\t\t0, c, - s, 0,\n\t\t\t0, s, c, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t},\n\n\tmakeRotationY: function ( theta ) {\n\n\t\tvar c = Math.cos( theta ), s = Math.sin( theta );\n\n\t\tthis.set(\n\n\t\t\t c, 0, s, 0,\n\t\t\t 0, 1, 0, 0,\n\t\t\t- s, 0, c, 0,\n\t\t\t 0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t},\n\n\tmakeRotationZ: function ( theta ) {\n\n\t\tvar c = Math.cos( theta ), s = Math.sin( theta );\n\n\t\tthis.set(\n\n\t\t\tc, - s, 0, 0,\n\t\t\ts, c, 0, 0,\n\t\t\t0, 0, 1, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t},\n\n\tmakeRotationAxis: function ( axis, angle ) {\n\n\t\t// Based on http://www.gamedev.net/reference/articles/article1199.asp\n\n\t\tvar c = Math.cos( angle );\n\t\tvar s = Math.sin( angle );\n\t\tvar t = 1 - c;\n\t\tvar x = axis.x, y = axis.y, z = axis.z;\n\t\tvar tx = t * x, ty = t * y;\n\n\t\tthis.set(\n\n\t\t\ttx * x + c, tx * y - s * z, tx * z + s * y, 0,\n\t\t\ttx * y + s * z, ty * y + c, ty * z - s * x, 0,\n\t\t\ttx * z - s * y, ty * z + s * x, t * z * z + c, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\t return this;\n\n\t},\n\n\tmakeScale: function ( x, y, z ) {\n\n\t\tthis.set(\n\n\t\t\tx, 0, 0, 0,\n\t\t\t0, y, 0, 0,\n\t\t\t0, 0, z, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t},\n\n\tmakeShear: function ( x, y, z ) {\n\n\t\tthis.set(\n\n\t\t\t1, y, z, 0,\n\t\t\tx, 1, z, 0,\n\t\t\tx, y, 1, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t},\n\n\tcompose: function ( position, quaternion, scale ) {\n\n\t\tthis.makeRotationFromQuaternion( quaternion );\n\t\tthis.scale( scale );\n\t\tthis.setPosition( position );\n\n\t\treturn this;\n\n\t},\n\n\tdecompose: function () {\n\n\t\tvar vector, matrix;\n\n\t\treturn function decompose( position, quaternion, scale ) {\n\n\t\t\tif ( vector === undefined ) {\n\n\t\t\t\tvector = new Vector3();\n\t\t\t\tmatrix = new Matrix4();\n\n\t\t\t}\n\n\t\t\tvar te = this.elements;\n\n\t\t\tvar sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();\n\t\t\tvar sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();\n\t\t\tvar sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();\n\n\t\t\t// if determine is negative, we need to invert one scale\n\t\t\tvar det = this.determinant();\n\t\t\tif ( det < 0 ) {\n\n\t\t\t\tsx = - sx;\n\n\t\t\t}\n\n\t\t\tposition.x = te[ 12 ];\n\t\t\tposition.y = te[ 13 ];\n\t\t\tposition.z = te[ 14 ];\n\n\t\t\t// scale the rotation part\n\n\t\t\tmatrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy()\n\n\t\t\tvar invSX = 1 / sx;\n\t\t\tvar invSY = 1 / sy;\n\t\t\tvar invSZ = 1 / sz;\n\n\t\t\tmatrix.elements[ 0 ] *= invSX;\n\t\t\tmatrix.elements[ 1 ] *= invSX;\n\t\t\tmatrix.elements[ 2 ] *= invSX;\n\n\t\t\tmatrix.elements[ 4 ] *= invSY;\n\t\t\tmatrix.elements[ 5 ] *= invSY;\n\t\t\tmatrix.elements[ 6 ] *= invSY;\n\n\t\t\tmatrix.elements[ 8 ] *= invSZ;\n\t\t\tmatrix.elements[ 9 ] *= invSZ;\n\t\t\tmatrix.elements[ 10 ] *= invSZ;\n\n\t\t\tquaternion.setFromRotationMatrix( matrix );\n\n\t\t\tscale.x = sx;\n\t\t\tscale.y = sy;\n\t\t\tscale.z = sz;\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\tmakePerspective: function ( left, right, top, bottom, near, far ) {\n\n\t\tif ( far === undefined ) {\n\n\t\t\tconsole.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' );\n\n\t\t}\n\n\t\tvar te = this.elements;\n\t\tvar x = 2 * near / ( right - left );\n\t\tvar y = 2 * near / ( top - bottom );\n\n\t\tvar a = ( right + left ) / ( right - left );\n\t\tvar b = ( top + bottom ) / ( top - bottom );\n\t\tvar c = - ( far + near ) / ( far - near );\n\t\tvar d = - 2 * far * near / ( far - near );\n\n\t\tte[ 0 ] = x;\tte[ 4 ] = 0;\tte[ 8 ] = a;\tte[ 12 ] = 0;\n\t\tte[ 1 ] = 0;\tte[ 5 ] = y;\tte[ 9 ] = b;\tte[ 13 ] = 0;\n\t\tte[ 2 ] = 0;\tte[ 6 ] = 0;\tte[ 10 ] = c;\tte[ 14 ] = d;\n\t\tte[ 3 ] = 0;\tte[ 7 ] = 0;\tte[ 11 ] = - 1;\tte[ 15 ] = 0;\n\n\t\treturn this;\n\n\t},\n\n\tmakeOrthographic: function ( left, right, top, bottom, near, far ) {\n\n\t\tvar te = this.elements;\n\t\tvar w = 1.0 / ( right - left );\n\t\tvar h = 1.0 / ( top - bottom );\n\t\tvar p = 1.0 / ( far - near );\n\n\t\tvar x = ( right + left ) * w;\n\t\tvar y = ( top + bottom ) * h;\n\t\tvar z = ( far + near ) * p;\n\n\t\tte[ 0 ] = 2 * w;\tte[ 4 ] = 0;\tte[ 8 ] = 0;\tte[ 12 ] = - x;\n\t\tte[ 1 ] = 0;\tte[ 5 ] = 2 * h;\tte[ 9 ] = 0;\tte[ 13 ] = - y;\n\t\tte[ 2 ] = 0;\tte[ 6 ] = 0;\tte[ 10 ] = - 2 * p;\tte[ 14 ] = - z;\n\t\tte[ 3 ] = 0;\tte[ 7 ] = 0;\tte[ 11 ] = 0;\tte[ 15 ] = 1;\n\n\t\treturn this;\n\n\t},\n\n\tequals: function ( matrix ) {\n\n\t\tvar te = this.elements;\n\t\tvar me = matrix.elements;\n\n\t\tfor ( var i = 0; i < 16; i ++ ) {\n\n\t\t\tif ( te[ i ] !== me[ i ] ) return false;\n\n\t\t}\n\n\t\treturn true;\n\n\t},\n\n\tfromArray: function ( array, offset ) {\n\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tfor( var i = 0; i < 16; i ++ ) {\n\n\t\t\tthis.elements[ i ] = array[ i + offset ];\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\ttoArray: function ( array, offset ) {\n\n\t\tif ( array === undefined ) array = [];\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tvar te = this.elements;\n\n\t\tarray[ offset ] = te[ 0 ];\n\t\tarray[ offset + 1 ] = te[ 1 ];\n\t\tarray[ offset + 2 ] = te[ 2 ];\n\t\tarray[ offset + 3 ] = te[ 3 ];\n\n\t\tarray[ offset + 4 ] = te[ 4 ];\n\t\tarray[ offset + 5 ] = te[ 5 ];\n\t\tarray[ offset + 6 ] = te[ 6 ];\n\t\tarray[ offset + 7 ] = te[ 7 ];\n\n\t\tarray[ offset + 8 ] = te[ 8 ];\n\t\tarray[ offset + 9 ] = te[ 9 ];\n\t\tarray[ offset + 10 ] = te[ 10 ];\n\t\tarray[ offset + 11 ] = te[ 11 ];\n\n\t\tarray[ offset + 12 ] = te[ 12 ];\n\t\tarray[ offset + 13 ] = te[ 13 ];\n\t\tarray[ offset + 14 ] = te[ 14 ];\n\t\tarray[ offset + 15 ] = te[ 15 ];\n\n\t\treturn array;\n\n\t}\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {\n\n\timages = images !== undefined ? images : [];\n\tmapping = mapping !== undefined ? mapping : CubeReflectionMapping;\n\n\tTexture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );\n\n\tthis.flipY = false;\n\n}\n\nCubeTexture.prototype = Object.create( Texture.prototype );\nCubeTexture.prototype.constructor = CubeTexture;\n\nCubeTexture.prototype.isCubeTexture = true;\n\nObject.defineProperty( CubeTexture.prototype, 'images', {\n\n\tget: function () {\n\n\t\treturn this.image;\n\n\t},\n\n\tset: function ( value ) {\n\n\t\tthis.image = value;\n\n\t}\n\n} );\n\n/**\n * @author tschw\n *\n * Uniforms of a program.\n * Those form a tree structure with a special top-level container for the root,\n * which you get by calling 'new WebGLUniforms( gl, program, renderer )'.\n *\n *\n * Properties of inner nodes including the top-level container:\n *\n * .seq - array of nested uniforms\n * .map - nested uniforms by name\n *\n *\n * Methods of all nodes except the top-level container:\n *\n * .setValue( gl, value, [renderer] )\n *\n * \t\tuploads a uniform value(s)\n * \tthe 'renderer' parameter is needed for sampler uniforms\n *\n *\n * Static methods of the top-level container (renderer factorizations):\n *\n * .upload( gl, seq, values, renderer )\n *\n * \t\tsets uniforms in 'seq' to 'values[id].value'\n *\n * .seqWithValue( seq, values ) : filteredSeq\n *\n * \t\tfilters 'seq' entries with corresponding entry in values\n *\n *\n * Methods of the top-level container (renderer factorizations):\n *\n * .setValue( gl, name, value )\n *\n * \t\tsets uniform with name 'name' to 'value'\n *\n * .set( gl, obj, prop )\n *\n * \t\tsets uniform from object and property with same name than uniform\n *\n * .setOptional( gl, obj, prop )\n *\n * \t\tlike .set for an optional property of the object\n *\n */\n\nvar emptyTexture = new Texture();\nvar emptyCubeTexture = new CubeTexture();\n\n// --- Base for inner nodes (including the root) ---\n\nfunction UniformContainer() {\n\n\tthis.seq = [];\n\tthis.map = {};\n\n}\n\n// --- Utilities ---\n\n// Array Caches (provide typed arrays for temporary by size)\n\nvar arrayCacheF32 = [];\nvar arrayCacheI32 = [];\n\n// Flattening for arrays of vectors and matrices\n\nfunction flatten( array, nBlocks, blockSize ) {\n\n\tvar firstElem = array[ 0 ];\n\n\tif ( firstElem <= 0 || firstElem > 0 ) return array;\n\t// unoptimized: ! isNaN( firstElem )\n\t// see http://jacksondunstan.com/articles/983\n\n\tvar n = nBlocks * blockSize,\n\t\tr = arrayCacheF32[ n ];\n\n\tif ( r === undefined ) {\n\n\t\tr = new Float32Array( n );\n\t\tarrayCacheF32[ n ] = r;\n\n\t}\n\n\tif ( nBlocks !== 0 ) {\n\n\t\tfirstElem.toArray( r, 0 );\n\n\t\tfor ( var i = 1, offset = 0; i !== nBlocks; ++ i ) {\n\n\t\t\toffset += blockSize;\n\t\t\tarray[ i ].toArray( r, offset );\n\n\t\t}\n\n\t}\n\n\treturn r;\n\n}\n\n// Texture unit allocation\n\nfunction allocTexUnits( renderer, n ) {\n\n\tvar r = arrayCacheI32[ n ];\n\n\tif ( r === undefined ) {\n\n\t\tr = new Int32Array( n );\n\t\tarrayCacheI32[ n ] = r;\n\n\t}\n\n\tfor ( var i = 0; i !== n; ++ i )\n\t\tr[ i ] = renderer.allocTextureUnit();\n\n\treturn r;\n\n}\n\n// --- Setters ---\n\n// Note: Defining these methods externally, because they come in a bunch\n// and this way their names minify.\n\n// Single scalar\n\nfunction setValue1f( gl, v ) { gl.uniform1f( this.addr, v ); }\nfunction setValue1i( gl, v ) { gl.uniform1i( this.addr, v ); }\n\n// Single float vector (from flat array or THREE.VectorN)\n\nfunction setValue2fv( gl, v ) {\n\n\tif ( v.x === undefined ) gl.uniform2fv( this.addr, v );\n\telse gl.uniform2f( this.addr, v.x, v.y );\n\n}\n\nfunction setValue3fv( gl, v ) {\n\n\tif ( v.x !== undefined )\n\t\tgl.uniform3f( this.addr, v.x, v.y, v.z );\n\telse if ( v.r !== undefined )\n\t\tgl.uniform3f( this.addr, v.r, v.g, v.b );\n\telse\n\t\tgl.uniform3fv( this.addr, v );\n\n}\n\nfunction setValue4fv( gl, v ) {\n\n\tif ( v.x === undefined ) gl.uniform4fv( this.addr, v );\n\telse gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );\n\n}\n\n// Single matrix (from flat array or MatrixN)\n\nfunction setValue2fm( gl, v ) {\n\n\tgl.uniformMatrix2fv( this.addr, false, v.elements || v );\n\n}\n\nfunction setValue3fm( gl, v ) {\n\n\tgl.uniformMatrix3fv( this.addr, false, v.elements || v );\n\n}\n\nfunction setValue4fm( gl, v ) {\n\n\tgl.uniformMatrix4fv( this.addr, false, v.elements || v );\n\n}\n\n// Single texture (2D / Cube)\n\nfunction setValueT1( gl, v, renderer ) {\n\n\tvar unit = renderer.allocTextureUnit();\n\tgl.uniform1i( this.addr, unit );\n\trenderer.setTexture2D( v || emptyTexture, unit );\n\n}\n\nfunction setValueT6( gl, v, renderer ) {\n\n\tvar unit = renderer.allocTextureUnit();\n\tgl.uniform1i( this.addr, unit );\n\trenderer.setTextureCube( v || emptyCubeTexture, unit );\n\n}\n\n// Integer / Boolean vectors or arrays thereof (always flat arrays)\n\nfunction setValue2iv( gl, v ) { gl.uniform2iv( this.addr, v ); }\nfunction setValue3iv( gl, v ) { gl.uniform3iv( this.addr, v ); }\nfunction setValue4iv( gl, v ) { gl.uniform4iv( this.addr, v ); }\n\n// Helper to pick the right setter for the singular case\n\nfunction getSingularSetter( type ) {\n\n\tswitch ( type ) {\n\n\t\tcase 0x1406: return setValue1f; // FLOAT\n\t\tcase 0x8b50: return setValue2fv; // _VEC2\n\t\tcase 0x8b51: return setValue3fv; // _VEC3\n\t\tcase 0x8b52: return setValue4fv; // _VEC4\n\n\t\tcase 0x8b5a: return setValue2fm; // _MAT2\n\t\tcase 0x8b5b: return setValue3fm; // _MAT3\n\t\tcase 0x8b5c: return setValue4fm; // _MAT4\n\n\t\tcase 0x8b5e: return setValueT1; // SAMPLER_2D\n\t\tcase 0x8b60: return setValueT6; // SAMPLER_CUBE\n\n\t\tcase 0x1404: case 0x8b56: return setValue1i; // INT, BOOL\n\t\tcase 0x8b53: case 0x8b57: return setValue2iv; // _VEC2\n\t\tcase 0x8b54: case 0x8b58: return setValue3iv; // _VEC3\n\t\tcase 0x8b55: case 0x8b59: return setValue4iv; // _VEC4\n\n\t}\n\n}\n\n// Array of scalars\n\nfunction setValue1fv( gl, v ) { gl.uniform1fv( this.addr, v ); }\nfunction setValue1iv( gl, v ) { gl.uniform1iv( this.addr, v ); }\n\n// Array of vectors (flat or from THREE classes)\n\nfunction setValueV2a( gl, v ) {\n\n\tgl.uniform2fv( this.addr, flatten( v, this.size, 2 ) );\n\n}\n\nfunction setValueV3a( gl, v ) {\n\n\tgl.uniform3fv( this.addr, flatten( v, this.size, 3 ) );\n\n}\n\nfunction setValueV4a( gl, v ) {\n\n\tgl.uniform4fv( this.addr, flatten( v, this.size, 4 ) );\n\n}\n\n// Array of matrices (flat or from THREE clases)\n\nfunction setValueM2a( gl, v ) {\n\n\tgl.uniformMatrix2fv( this.addr, false, flatten( v, this.size, 4 ) );\n\n}\n\nfunction setValueM3a( gl, v ) {\n\n\tgl.uniformMatrix3fv( this.addr, false, flatten( v, this.size, 9 ) );\n\n}\n\nfunction setValueM4a( gl, v ) {\n\n\tgl.uniformMatrix4fv( this.addr, false, flatten( v, this.size, 16 ) );\n\n}\n\n// Array of textures (2D / Cube)\n\nfunction setValueT1a( gl, v, renderer ) {\n\n\tvar n = v.length,\n\t\tunits = allocTexUnits( renderer, n );\n\n\tgl.uniform1iv( this.addr, units );\n\n\tfor ( var i = 0; i !== n; ++ i ) {\n\n\t\trenderer.setTexture2D( v[ i ] || emptyTexture, units[ i ] );\n\n\t}\n\n}\n\nfunction setValueT6a( gl, v, renderer ) {\n\n\tvar n = v.length,\n\t\tunits = allocTexUnits( renderer, n );\n\n\tgl.uniform1iv( this.addr, units );\n\n\tfor ( var i = 0; i !== n; ++ i ) {\n\n\t\trenderer.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );\n\n\t}\n\n}\n\n// Helper to pick the right setter for a pure (bottom-level) array\n\nfunction getPureArraySetter( type ) {\n\n\tswitch ( type ) {\n\n\t\tcase 0x1406: return setValue1fv; // FLOAT\n\t\tcase 0x8b50: return setValueV2a; // _VEC2\n\t\tcase 0x8b51: return setValueV3a; // _VEC3\n\t\tcase 0x8b52: return setValueV4a; // _VEC4\n\n\t\tcase 0x8b5a: return setValueM2a; // _MAT2\n\t\tcase 0x8b5b: return setValueM3a; // _MAT3\n\t\tcase 0x8b5c: return setValueM4a; // _MAT4\n\n\t\tcase 0x8b5e: return setValueT1a; // SAMPLER_2D\n\t\tcase 0x8b60: return setValueT6a; // SAMPLER_CUBE\n\n\t\tcase 0x1404: case 0x8b56: return setValue1iv; // INT, BOOL\n\t\tcase 0x8b53: case 0x8b57: return setValue2iv; // _VEC2\n\t\tcase 0x8b54: case 0x8b58: return setValue3iv; // _VEC3\n\t\tcase 0x8b55: case 0x8b59: return setValue4iv; // _VEC4\n\n\t}\n\n}\n\n// --- Uniform Classes ---\n\nfunction SingleUniform( id, activeInfo, addr ) {\n\n\tthis.id = id;\n\tthis.addr = addr;\n\tthis.setValue = getSingularSetter( activeInfo.type );\n\n\t// this.path = activeInfo.name; // DEBUG\n\n}\n\nfunction PureArrayUniform( id, activeInfo, addr ) {\n\n\tthis.id = id;\n\tthis.addr = addr;\n\tthis.size = activeInfo.size;\n\tthis.setValue = getPureArraySetter( activeInfo.type );\n\n\t// this.path = activeInfo.name; // DEBUG\n\n}\n\nfunction StructuredUniform( id ) {\n\n\tthis.id = id;\n\n\tUniformContainer.call( this ); // mix-in\n\n}\n\nStructuredUniform.prototype.setValue = function( gl, value ) {\n\n\t// Note: Don't need an extra 'renderer' parameter, since samplers\n\t// are not allowed in structured uniforms.\n\n\tvar seq = this.seq;\n\n\tfor ( var i = 0, n = seq.length; i !== n; ++ i ) {\n\n\t\tvar u = seq[ i ];\n\t\tu.setValue( gl, value[ u.id ] );\n\n\t}\n\n};\n\n// --- Top-level ---\n\n// Parser - builds up the property tree from the path strings\n\nvar RePathPart = /([\\w\\d_]+)(\\])?(\\[|\\.)?/g;\n\n// extracts\n// \t- the identifier (member name or array index)\n// - followed by an optional right bracket (found when array index)\n// - followed by an optional left bracket or dot (type of subscript)\n//\n// Note: These portions can be read in a non-overlapping fashion and\n// allow straightforward parsing of the hierarchy that WebGL encodes\n// in the uniform names.\n\nfunction addUniform( container, uniformObject ) {\n\n\tcontainer.seq.push( uniformObject );\n\tcontainer.map[ uniformObject.id ] = uniformObject;\n\n}\n\nfunction parseUniform( activeInfo, addr, container ) {\n\n\tvar path = activeInfo.name,\n\t\tpathLength = path.length;\n\n\t// reset RegExp object, because of the early exit of a previous run\n\tRePathPart.lastIndex = 0;\n\n\tfor (; ;) {\n\n\t\tvar match = RePathPart.exec( path ),\n\t\t\tmatchEnd = RePathPart.lastIndex,\n\n\t\t\tid = match[ 1 ],\n\t\t\tidIsIndex = match[ 2 ] === ']',\n\t\t\tsubscript = match[ 3 ];\n\n\t\tif ( idIsIndex ) id = id | 0; // convert to integer\n\n\t\tif ( subscript === undefined ||\n\t\t\t\tsubscript === '[' && matchEnd + 2 === pathLength ) {\n\t\t\t// bare name or \"pure\" bottom-level array \"[0]\" suffix\n\n\t\t\taddUniform( container, subscript === undefined ?\n\t\t\t\t\tnew SingleUniform( id, activeInfo, addr ) :\n\t\t\t\t\tnew PureArrayUniform( id, activeInfo, addr ) );\n\n\t\t\tbreak;\n\n\t\t} else {\n\t\t\t// step into inner node / create it in case it doesn't exist\n\n\t\t\tvar map = container.map,\n\t\t\t\tnext = map[ id ];\n\n\t\t\tif ( next === undefined ) {\n\n\t\t\t\tnext = new StructuredUniform( id );\n\t\t\t\taddUniform( container, next );\n\n\t\t\t}\n\n\t\t\tcontainer = next;\n\n\t\t}\n\n\t}\n\n}\n\n// Root Container\n\nfunction WebGLUniforms( gl, program, renderer ) {\n\n\tUniformContainer.call( this );\n\n\tthis.renderer = renderer;\n\n\tvar n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );\n\n\tfor ( var i = 0; i < n; ++ i ) {\n\n\t\tvar info = gl.getActiveUniform( program, i ),\n\t\t\tpath = info.name,\n\t\t\taddr = gl.getUniformLocation( program, path );\n\n\t\tparseUniform( info, addr, this );\n\n\t}\n\n}\n\nWebGLUniforms.prototype.setValue = function( gl, name, value ) {\n\n\tvar u = this.map[ name ];\n\n\tif ( u !== undefined ) u.setValue( gl, value, this.renderer );\n\n};\n\nWebGLUniforms.prototype.set = function( gl, object, name ) {\n\n\tvar u = this.map[ name ];\n\n\tif ( u !== undefined ) u.setValue( gl, object[ name ], this.renderer );\n\n};\n\nWebGLUniforms.prototype.setOptional = function( gl, object, name ) {\n\n\tvar v = object[ name ];\n\n\tif ( v !== undefined ) this.setValue( gl, name, v );\n\n};\n\n\n// Static interface\n\nWebGLUniforms.upload = function( gl, seq, values, renderer ) {\n\n\tfor ( var i = 0, n = seq.length; i !== n; ++ i ) {\n\n\t\tvar u = seq[ i ],\n\t\t\tv = values[ u.id ];\n\n\t\tif ( v.needsUpdate !== false ) {\n\t\t\t// note: always updating when .needsUpdate is undefined\n\n\t\t\tu.setValue( gl, v.value, renderer );\n\n\t\t}\n\n\t}\n\n};\n\nWebGLUniforms.seqWithValue = function( seq, values ) {\n\n\tvar r = [];\n\n\tfor ( var i = 0, n = seq.length; i !== n; ++ i ) {\n\n\t\tvar u = seq[ i ];\n\t\tif ( u.id in values ) r.push( u );\n\n\t}\n\n\treturn r;\n\n};\n\n/**\n * Uniform Utilities\n */\n\nvar UniformsUtils = {\n\n\tmerge: function ( uniforms ) {\n\n\t\tvar merged = {};\n\n\t\tfor ( var u = 0; u < uniforms.length; u ++ ) {\n\n\t\t\tvar tmp = this.clone( uniforms[ u ] );\n\n\t\t\tfor ( var p in tmp ) {\n\n\t\t\t\tmerged[ p ] = tmp[ p ];\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn merged;\n\n\t},\n\n\tclone: function ( uniforms_src ) {\n\n\t\tvar uniforms_dst = {};\n\n\t\tfor ( var u in uniforms_src ) {\n\n\t\t\tuniforms_dst[ u ] = {};\n\n\t\t\tfor ( var p in uniforms_src[ u ] ) {\n\n\t\t\t\tvar parameter_src = uniforms_src[ u ][ p ];\n\n\t\t\t\tif ( parameter_src && ( parameter_src.isColor ||\n\t\t\t\t\tparameter_src.isMatrix3 || parameter_src.isMatrix4 ||\n\t\t\t\t\tparameter_src.isVector2 || parameter_src.isVector3 || parameter_src.isVector4 ||\n\t\t\t\t\tparameter_src.isTexture ) ) {\n\n\t\t\t\t\tuniforms_dst[ u ][ p ] = parameter_src.clone();\n\n\t\t\t\t} else if ( Array.isArray( parameter_src ) ) {\n\n\t\t\t\t\tuniforms_dst[ u ][ p ] = parameter_src.slice();\n\n\t\t\t\t} else {\n\n\t\t\t\t\tuniforms_dst[ u ][ p ] = parameter_src;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn uniforms_dst;\n\n\t}\n\n};\n\nvar alphamap_fragment = \"#ifdef USE_ALPHAMAP\\n\\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\\n#endif\\n\";\n\nvar alphamap_pars_fragment = \"#ifdef USE_ALPHAMAP\\n\\tuniform sampler2D alphaMap;\\n#endif\\n\";\n\nvar alphatest_fragment = \"#ifdef ALPHATEST\\n\\tif ( diffuseColor.a < ALPHATEST ) discard;\\n#endif\\n\";\n\nvar aomap_fragment = \"#ifdef USE_AOMAP\\n\\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\\n\\treflectedLight.indirectDiffuse *= ambientOcclusion;\\n\\t#if defined( USE_ENVMAP ) && defined( PHYSICAL )\\n\\t\\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\\n\\t\\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\\n\\t#endif\\n#endif\\n\";\n\nvar aomap_pars_fragment = \"#ifdef USE_AOMAP\\n\\tuniform sampler2D aoMap;\\n\\tuniform float aoMapIntensity;\\n#endif\";\n\nvar begin_vertex = \"\\nvec3 transformed = vec3( position );\\n\";\n\nvar beginnormal_vertex = \"\\nvec3 objectNormal = vec3( normal );\\n\";\n\nvar bsdfs = \"float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\\n\\t\\tif( decayExponent > 0.0 ) {\\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\\n\\t\\t\\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\\n\\t\\t\\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\\n\\t\\t\\treturn distanceFalloff * maxDistanceCutoffFactor;\\n#else\\n\\t\\t\\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\\n#endif\\n\\t\\t}\\n\\t\\treturn 1.0;\\n}\\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\\n\\treturn RECIPROCAL_PI * diffuseColor;\\n}\\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\\n\\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\\n\\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\\n}\\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\\n\\tfloat a2 = pow2( alpha );\\n\\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\\n\\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\\n\\treturn 1.0 / ( gl * gv );\\n}\\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\\n\\tfloat a2 = pow2( alpha );\\n\\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\\n\\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\\n\\treturn 0.5 / max( gv + gl, EPSILON );\\n}\\nfloat D_GGX( const in float alpha, const in float dotNH ) {\\n\\tfloat a2 = pow2( alpha );\\n\\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\\n\\treturn RECIPROCAL_PI * a2 / pow2( denom );\\n}\\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\\n\\tfloat alpha = pow2( roughness );\\n\\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\\n\\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\\n\\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\\n\\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\\n\\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\\n\\tvec3 F = F_Schlick( specularColor, dotLH );\\n\\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\\n\\tfloat D = D_GGX( alpha, dotNH );\\n\\treturn F * ( G * D );\\n}\\nvec2 ltcTextureCoords( const in GeometricContext geometry, const in float roughness ) {\\n\\tconst float LUT_SIZE = 64.0;\\n\\tconst float LUT_SCALE = (LUT_SIZE - 1.0)/LUT_SIZE;\\n\\tconst float LUT_BIAS = 0.5/LUT_SIZE;\\n\\tvec3 N = geometry.normal;\\n\\tvec3 V = geometry.viewDir;\\n\\tvec3 P = geometry.position;\\n\\tfloat theta = acos( dot( N, V ) );\\n\\tvec2 uv = vec2(\\n\\t\\tsqrt( saturate( roughness ) ),\\n\\t\\tsaturate( theta / ( 0.5 * PI ) ) );\\n\\tuv = uv * LUT_SCALE + LUT_BIAS;\\n\\treturn uv;\\n}\\nvoid clipQuadToHorizon( inout vec3 L[5], out int n ) {\\n\\tint config = 0;\\n\\tif ( L[0].z > 0.0 ) config += 1;\\n\\tif ( L[1].z > 0.0 ) config += 2;\\n\\tif ( L[2].z > 0.0 ) config += 4;\\n\\tif ( L[3].z > 0.0 ) config += 8;\\n\\tn = 0;\\n\\tif ( config == 0 ) {\\n\\t} else if ( config == 1 ) {\\n\\t\\tn = 3;\\n\\t\\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\\n\\t\\tL[2] = -L[3].z * L[0] + L[0].z * L[3];\\n\\t} else if ( config == 2 ) {\\n\\t\\tn = 3;\\n\\t\\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\\n\\t\\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\\n\\t} else if ( config == 3 ) {\\n\\t\\tn = 4;\\n\\t\\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\\n\\t\\tL[3] = -L[3].z * L[0] + L[0].z * L[3];\\n\\t} else if ( config == 4 ) {\\n\\t\\tn = 3;\\n\\t\\tL[0] = -L[3].z * L[2] + L[2].z * L[3];\\n\\t\\tL[1] = -L[1].z * L[2] + L[2].z * L[1];\\n\\t} else if ( config == 5 ) {\\n\\t\\tn = 0;\\n\\t} else if ( config == 6 ) {\\n\\t\\tn = 4;\\n\\t\\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\\n\\t\\tL[3] = -L[3].z * L[2] + L[2].z * L[3];\\n\\t} else if ( config == 7 ) {\\n\\t\\tn = 5;\\n\\t\\tL[4] = -L[3].z * L[0] + L[0].z * L[3];\\n\\t\\tL[3] = -L[3].z * L[2] + L[2].z * L[3];\\n\\t} else if ( config == 8 ) {\\n\\t\\tn = 3;\\n\\t\\tL[0] = -L[0].z * L[3] + L[3].z * L[0];\\n\\t\\tL[1] = -L[2].z * L[3] + L[3].z * L[2];\\n\\t\\tL[2] = L[3];\\n\\t} else if ( config == 9 ) {\\n\\t\\tn = 4;\\n\\t\\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\\n\\t\\tL[2] = -L[2].z * L[3] + L[3].z * L[2];\\n\\t} else if ( config == 10 ) {\\n\\t\\tn = 0;\\n\\t} else if ( config == 11 ) {\\n\\t\\tn = 5;\\n\\t\\tL[4] = L[3];\\n\\t\\tL[3] = -L[2].z * L[3] + L[3].z * L[2];\\n\\t\\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\\n\\t} else if ( config == 12 ) {\\n\\t\\tn = 4;\\n\\t\\tL[1] = -L[1].z * L[2] + L[2].z * L[1];\\n\\t\\tL[0] = -L[0].z * L[3] + L[3].z * L[0];\\n\\t} else if ( config == 13 ) {\\n\\t\\tn = 5;\\n\\t\\tL[4] = L[3];\\n\\t\\tL[3] = L[2];\\n\\t\\tL[2] = -L[1].z * L[2] + L[2].z * L[1];\\n\\t\\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\\n\\t} else if ( config == 14 ) {\\n\\t\\tn = 5;\\n\\t\\tL[4] = -L[0].z * L[3] + L[3].z * L[0];\\n\\t\\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\\n\\t} else if ( config == 15 ) {\\n\\t\\tn = 4;\\n\\t}\\n\\tif ( n == 3 )\\n\\t\\tL[3] = L[0];\\n\\tif ( n == 4 )\\n\\t\\tL[4] = L[0];\\n}\\nfloat integrateLtcBrdfOverRectEdge( vec3 v1, vec3 v2 ) {\\n\\tfloat cosTheta = dot( v1, v2 );\\n\\tfloat theta = acos( cosTheta );\\n\\tfloat res = cross( v1, v2 ).z * ( ( theta > 0.001 ) ? theta / sin( theta ) : 1.0 );\\n\\treturn res;\\n}\\nvoid initRectPoints( const in vec3 pos, const in vec3 halfWidth, const in vec3 halfHeight, out vec3 rectPoints[4] ) {\\n\\trectPoints[0] = pos - halfWidth - halfHeight;\\n\\trectPoints[1] = pos + halfWidth - halfHeight;\\n\\trectPoints[2] = pos + halfWidth + halfHeight;\\n\\trectPoints[3] = pos - halfWidth + halfHeight;\\n}\\nvec3 integrateLtcBrdfOverRect( const in GeometricContext geometry, const in mat3 brdfMat, const in vec3 rectPoints[4] ) {\\n\\tvec3 N = geometry.normal;\\n\\tvec3 V = geometry.viewDir;\\n\\tvec3 P = geometry.position;\\n\\tvec3 T1, T2;\\n\\tT1 = normalize(V - N * dot( V, N ));\\n\\tT2 = - cross( N, T1 );\\n\\tmat3 brdfWrtSurface = brdfMat * transpose( mat3( T1, T2, N ) );\\n\\tvec3 clippedRect[5];\\n\\tclippedRect[0] = brdfWrtSurface * ( rectPoints[0] - P );\\n\\tclippedRect[1] = brdfWrtSurface * ( rectPoints[1] - P );\\n\\tclippedRect[2] = brdfWrtSurface * ( rectPoints[2] - P );\\n\\tclippedRect[3] = brdfWrtSurface * ( rectPoints[3] - P );\\n\\tint n;\\n\\tclipQuadToHorizon(clippedRect, n);\\n\\tif ( n == 0 )\\n\\t\\treturn vec3( 0, 0, 0 );\\n\\tclippedRect[0] = normalize( clippedRect[0] );\\n\\tclippedRect[1] = normalize( clippedRect[1] );\\n\\tclippedRect[2] = normalize( clippedRect[2] );\\n\\tclippedRect[3] = normalize( clippedRect[3] );\\n\\tclippedRect[4] = normalize( clippedRect[4] );\\n\\tfloat sum = 0.0;\\n\\tsum += integrateLtcBrdfOverRectEdge( clippedRect[0], clippedRect[1] );\\n\\tsum += integrateLtcBrdfOverRectEdge( clippedRect[1], clippedRect[2] );\\n\\tsum += integrateLtcBrdfOverRectEdge( clippedRect[2], clippedRect[3] );\\n\\tif (n >= 4)\\n\\t\\tsum += integrateLtcBrdfOverRectEdge( clippedRect[3], clippedRect[4] );\\n\\tif (n == 5)\\n\\t\\tsum += integrateLtcBrdfOverRectEdge( clippedRect[4], clippedRect[0] );\\n\\tsum = max( 0.0, sum );\\n\\tvec3 Lo_i = vec3( sum, sum, sum );\\n\\treturn Lo_i;\\n}\\nvec3 Rect_Area_Light_Specular_Reflectance(\\n\\t\\tconst in GeometricContext geometry,\\n\\t\\tconst in vec3 lightPos, const in vec3 lightHalfWidth, const in vec3 lightHalfHeight,\\n\\t\\tconst in float roughness,\\n\\t\\tconst in sampler2D ltcMat, const in sampler2D ltcMag ) {\\n\\tvec3 rectPoints[4];\\n\\tinitRectPoints( lightPos, lightHalfWidth, lightHalfHeight, rectPoints );\\n\\tvec2 uv = ltcTextureCoords( geometry, roughness );\\n\\tvec4 brdfLtcApproxParams, t;\\n\\tbrdfLtcApproxParams = texture2D( ltcMat, uv );\\n\\tt = texture2D( ltcMat, uv );\\n\\tfloat brdfLtcScalar = texture2D( ltcMag, uv ).a;\\n\\tmat3 brdfLtcApproxMat = mat3(\\n\\t\\tvec3( 1, 0, t.y ),\\n\\t\\tvec3( 0, t.z, 0 ),\\n\\t\\tvec3( t.w, 0, t.x )\\n\\t);\\n\\tvec3 specularReflectance = integrateLtcBrdfOverRect( geometry, brdfLtcApproxMat, rectPoints );\\n\\tspecularReflectance *= brdfLtcScalar;\\n\\treturn specularReflectance;\\n}\\nvec3 Rect_Area_Light_Diffuse_Reflectance(\\n\\t\\tconst in GeometricContext geometry,\\n\\t\\tconst in vec3 lightPos, const in vec3 lightHalfWidth, const in vec3 lightHalfHeight ) {\\n\\tvec3 rectPoints[4];\\n\\tinitRectPoints( lightPos, lightHalfWidth, lightHalfHeight, rectPoints );\\n\\tmat3 diffuseBrdfMat = mat3(1);\\n\\tvec3 diffuseReflectance = integrateLtcBrdfOverRect( geometry, diffuseBrdfMat, rectPoints );\\n\\treturn diffuseReflectance;\\n}\\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\\n\\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\\n\\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\\n\\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\\n\\tvec4 r = roughness * c0 + c1;\\n\\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\\n\\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\\n\\treturn specularColor * AB.x + AB.y;\\n}\\nfloat G_BlinnPhong_Implicit( ) {\\n\\treturn 0.25;\\n}\\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\\n\\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\\n}\\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\\n\\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\\n\\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\\n\\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\\n\\tvec3 F = F_Schlick( specularColor, dotLH );\\n\\tfloat G = G_BlinnPhong_Implicit( );\\n\\tfloat D = D_BlinnPhong( shininess, dotNH );\\n\\treturn F * ( G * D );\\n}\\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\\n\\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\\n}\\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\\n\\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\\n}\\n\";\n\nvar bumpmap_pars_fragment = \"#ifdef USE_BUMPMAP\\n\\tuniform sampler2D bumpMap;\\n\\tuniform float bumpScale;\\n\\tvec2 dHdxy_fwd() {\\n\\t\\tvec2 dSTdx = dFdx( vUv );\\n\\t\\tvec2 dSTdy = dFdy( vUv );\\n\\t\\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\\n\\t\\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\\n\\t\\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\\n\\t\\treturn vec2( dBx, dBy );\\n\\t}\\n\\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\\n\\t\\tvec3 vSigmaX = dFdx( surf_pos );\\n\\t\\tvec3 vSigmaY = dFdy( surf_pos );\\n\\t\\tvec3 vN = surf_norm;\\n\\t\\tvec3 R1 = cross( vSigmaY, vN );\\n\\t\\tvec3 R2 = cross( vN, vSigmaX );\\n\\t\\tfloat fDet = dot( vSigmaX, R1 );\\n\\t\\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\\n\\t\\treturn normalize( abs( fDet ) * surf_norm - vGrad );\\n\\t}\\n#endif\\n\";\n\nvar clipping_planes_fragment = \"#if NUM_CLIPPING_PLANES > 0\\n\\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; ++ i ) {\\n\\t\\tvec4 plane = clippingPlanes[ i ];\\n\\t\\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\\n\\t}\\n\\t\\t\\n\\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\\n\\t\\tbool clipped = true;\\n\\t\\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; ++ i ) {\\n\\t\\t\\tvec4 plane = clippingPlanes[ i ];\\n\\t\\t\\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\\n\\t\\t}\\n\\t\\tif ( clipped ) discard;\\n\\t\\n\\t#endif\\n#endif\\n\";\n\nvar clipping_planes_pars_fragment = \"#if NUM_CLIPPING_PLANES > 0\\n\\t#if ! defined( PHYSICAL ) && ! defined( PHONG )\\n\\t\\tvarying vec3 vViewPosition;\\n\\t#endif\\n\\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\\n#endif\\n\";\n\nvar clipping_planes_pars_vertex = \"#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\\n\\tvarying vec3 vViewPosition;\\n#endif\\n\";\n\nvar clipping_planes_vertex = \"#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\\n\\tvViewPosition = - mvPosition.xyz;\\n#endif\\n\";\n\nvar color_fragment = \"#ifdef USE_COLOR\\n\\tdiffuseColor.rgb *= vColor;\\n#endif\";\n\nvar color_pars_fragment = \"#ifdef USE_COLOR\\n\\tvarying vec3 vColor;\\n#endif\\n\";\n\nvar color_pars_vertex = \"#ifdef USE_COLOR\\n\\tvarying vec3 vColor;\\n#endif\";\n\nvar color_vertex = \"#ifdef USE_COLOR\\n\\tvColor.xyz = color.xyz;\\n#endif\";\n\nvar common = \"#define PI 3.14159265359\\n#define PI2 6.28318530718\\n#define PI_HALF 1.5707963267949\\n#define RECIPROCAL_PI 0.31830988618\\n#define RECIPROCAL_PI2 0.15915494\\n#define LOG2 1.442695\\n#define EPSILON 1e-6\\n#define saturate(a) clamp( a, 0.0, 1.0 )\\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\\nfloat pow2( const in float x ) { return x*x; }\\nfloat pow3( const in float x ) { return x*x*x; }\\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\\nhighp float rand( const in vec2 uv ) {\\n\\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\\n\\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\\n\\treturn fract(sin(sn) * c);\\n}\\nstruct IncidentLight {\\n\\tvec3 color;\\n\\tvec3 direction;\\n\\tbool visible;\\n};\\nstruct ReflectedLight {\\n\\tvec3 directDiffuse;\\n\\tvec3 directSpecular;\\n\\tvec3 indirectDiffuse;\\n\\tvec3 indirectSpecular;\\n};\\nstruct GeometricContext {\\n\\tvec3 position;\\n\\tvec3 normal;\\n\\tvec3 viewDir;\\n};\\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\\n\\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\\n}\\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\\n\\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\\n}\\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\\n\\tfloat distance = dot( planeNormal, point - pointOnPlane );\\n\\treturn - distance * planeNormal + point;\\n}\\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\\n\\treturn sign( dot( point - pointOnPlane, planeNormal ) );\\n}\\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\\n\\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\\n}\\nmat3 transpose( const in mat3 v ) {\\n\\tmat3 tmp;\\n\\ttmp[0] = vec3(v[0].x, v[1].x, v[2].x);\\n\\ttmp[1] = vec3(v[0].y, v[1].y, v[2].y);\\n\\ttmp[2] = vec3(v[0].z, v[1].z, v[2].z);\\n\\treturn tmp;\\n}\\n\";\n\nvar cube_uv_reflection_fragment = \"#ifdef ENVMAP_TYPE_CUBE_UV\\n#define cubeUV_textureSize (1024.0)\\nint getFaceFromDirection(vec3 direction) {\\n\\tvec3 absDirection = abs(direction);\\n\\tint face = -1;\\n\\tif( absDirection.x > absDirection.z ) {\\n\\t\\tif(absDirection.x > absDirection.y )\\n\\t\\t\\tface = direction.x > 0.0 ? 0 : 3;\\n\\t\\telse\\n\\t\\t\\tface = direction.y > 0.0 ? 1 : 4;\\n\\t}\\n\\telse {\\n\\t\\tif(absDirection.z > absDirection.y )\\n\\t\\t\\tface = direction.z > 0.0 ? 2 : 5;\\n\\t\\telse\\n\\t\\t\\tface = direction.y > 0.0 ? 1 : 4;\\n\\t}\\n\\treturn face;\\n}\\n#define cubeUV_maxLods1 (log2(cubeUV_textureSize*0.25) - 1.0)\\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\\n\\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\\n\\tfloat dxRoughness = dFdx(roughness);\\n\\tfloat dyRoughness = dFdy(roughness);\\n\\tvec3 dx = dFdx( vec * scale * dxRoughness );\\n\\tvec3 dy = dFdy( vec * scale * dyRoughness );\\n\\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\\n\\td = clamp(d, 1.0, cubeUV_rangeClamp);\\n\\tfloat mipLevel = 0.5 * log2(d);\\n\\treturn vec2(floor(mipLevel), fract(mipLevel));\\n}\\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\\n\\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\\n\\tfloat a = 16.0 * cubeUV_rcpTextureSize;\\n\\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\\n\\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\\n\\tfloat powScale = exp2_packed.x * exp2_packed.y;\\n\\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\\n\\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\\n\\tbool bRes = mipLevel == 0.0;\\n\\tscale = bRes && (scale < a) ? a : scale;\\n\\tvec3 r;\\n\\tvec2 offset;\\n\\tint face = getFaceFromDirection(direction);\\n\\tfloat rcpPowScale = 1.0 / powScale;\\n\\tif( face == 0) {\\n\\t\\tr = vec3(direction.x, -direction.z, direction.y);\\n\\t\\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\\n\\t\\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\\n\\t}\\n\\telse if( face == 1) {\\n\\t\\tr = vec3(direction.y, direction.x, direction.z);\\n\\t\\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\\n\\t\\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\\n\\t}\\n\\telse if( face == 2) {\\n\\t\\tr = vec3(direction.z, direction.x, direction.y);\\n\\t\\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\\n\\t\\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\\n\\t}\\n\\telse if( face == 3) {\\n\\t\\tr = vec3(direction.x, direction.z, direction.y);\\n\\t\\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\\n\\t\\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\\n\\t}\\n\\telse if( face == 4) {\\n\\t\\tr = vec3(direction.y, direction.x, -direction.z);\\n\\t\\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\\n\\t\\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\\n\\t}\\n\\telse {\\n\\t\\tr = vec3(direction.z, -direction.x, direction.y);\\n\\t\\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\\n\\t\\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\\n\\t}\\n\\tr = normalize(r);\\n\\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\\n\\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\\n\\tvec2 base = offset + vec2( texelOffset );\\n\\treturn base + s * ( scale - 2.0 * texelOffset );\\n}\\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\\nvec4 textureCubeUV(vec3 reflectedDirection, float roughness ) {\\n\\tfloat roughnessVal = roughness* cubeUV_maxLods3;\\n\\tfloat r1 = floor(roughnessVal);\\n\\tfloat r2 = r1 + 1.0;\\n\\tfloat t = fract(roughnessVal);\\n\\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\\n\\tfloat s = mipInfo.y;\\n\\tfloat level0 = mipInfo.x;\\n\\tfloat level1 = level0 + 1.0;\\n\\tlevel1 = level1 > 5.0 ? 5.0 : level1;\\n\\tlevel0 += min( floor( s + 0.5 ), 5.0 );\\n\\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\\n\\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\\n\\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\\n\\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\\n\\tvec4 result = mix(color10, color20, t);\\n\\treturn vec4(result.rgb, 1.0);\\n}\\n#endif\\n\";\n\nvar defaultnormal_vertex = \"#ifdef FLIP_SIDED\\n\\tobjectNormal = -objectNormal;\\n#endif\\nvec3 transformedNormal = normalMatrix * objectNormal;\\n\";\n\nvar displacementmap_pars_vertex = \"#ifdef USE_DISPLACEMENTMAP\\n\\tuniform sampler2D displacementMap;\\n\\tuniform float displacementScale;\\n\\tuniform float displacementBias;\\n#endif\\n\";\n\nvar displacementmap_vertex = \"#ifdef USE_DISPLACEMENTMAP\\n\\ttransformed += normal * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\\n#endif\\n\";\n\nvar emissivemap_fragment = \"#ifdef USE_EMISSIVEMAP\\n\\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\\n\\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\\n\\ttotalEmissiveRadiance *= emissiveColor.rgb;\\n#endif\\n\";\n\nvar emissivemap_pars_fragment = \"#ifdef USE_EMISSIVEMAP\\n\\tuniform sampler2D emissiveMap;\\n#endif\\n\";\n\nvar encodings_fragment = \" gl_FragColor = linearToOutputTexel( gl_FragColor );\\n\";\n\nvar encodings_pars_fragment = \"\\nvec4 LinearToLinear( in vec4 value ) {\\n\\treturn value;\\n}\\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\\n\\treturn vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );\\n}\\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\\n\\treturn vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );\\n}\\nvec4 sRGBToLinear( in vec4 value ) {\\n\\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );\\n}\\nvec4 LinearTosRGB( in vec4 value ) {\\n\\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );\\n}\\nvec4 RGBEToLinear( in vec4 value ) {\\n\\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\\n}\\nvec4 LinearToRGBE( in vec4 value ) {\\n\\tfloat maxComponent = max( max( value.r, value.g ), value.b );\\n\\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\\n\\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\\n}\\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\\n\\treturn vec4( value.xyz * value.w * maxRange, 1.0 );\\n}\\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\\n\\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\\n\\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\\n\\tM = ceil( M * 255.0 ) / 255.0;\\n\\treturn vec4( value.rgb / ( M * maxRange ), M );\\n}\\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\\n\\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\\n}\\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\\n\\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\\n\\tfloat D = max( maxRange / maxRGB, 1.0 );\\n\\tD = min( floor( D ) / 255.0, 1.0 );\\n\\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\\n}\\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\\nvec4 LinearToLogLuv( in vec4 value ) {\\n\\tvec3 Xp_Y_XYZp = value.rgb * cLogLuvM;\\n\\tXp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));\\n\\tvec4 vResult;\\n\\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\\n\\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\\n\\tvResult.w = fract(Le);\\n\\tvResult.z = (Le - (floor(vResult.w*255.0))/255.0)/255.0;\\n\\treturn vResult;\\n}\\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\\nvec4 LogLuvToLinear( in vec4 value ) {\\n\\tfloat Le = value.z * 255.0 + value.w;\\n\\tvec3 Xp_Y_XYZp;\\n\\tXp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);\\n\\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\\n\\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\\n\\tvec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;\\n\\treturn vec4( max(vRGB, 0.0), 1.0 );\\n}\\n\";\n\nvar envmap_fragment = \"#ifdef USE_ENVMAP\\n\\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\\n\\t\\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\\n\\t\\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\\n\\t\\t#ifdef ENVMAP_MODE_REFLECTION\\n\\t\\t\\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\\n\\t\\t#else\\n\\t\\t\\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\\n\\t\\t#endif\\n\\t#else\\n\\t\\tvec3 reflectVec = vReflect;\\n\\t#endif\\n\\t#ifdef ENVMAP_TYPE_CUBE\\n\\t\\tvec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\\n\\t#elif defined( ENVMAP_TYPE_EQUIREC )\\n\\t\\tvec2 sampleUV;\\n\\t\\tsampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\\n\\t\\tsampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\\n\\t\\tvec4 envColor = texture2D( envMap, sampleUV );\\n\\t#elif defined( ENVMAP_TYPE_SPHERE )\\n\\t\\tvec3 reflectView = flipNormal * normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\\n\\t\\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\\n\\t#else\\n\\t\\tvec4 envColor = vec4( 0.0 );\\n\\t#endif\\n\\tenvColor = envMapTexelToLinear( envColor );\\n\\t#ifdef ENVMAP_BLENDING_MULTIPLY\\n\\t\\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\\n\\t#elif defined( ENVMAP_BLENDING_MIX )\\n\\t\\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\\n\\t#elif defined( ENVMAP_BLENDING_ADD )\\n\\t\\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\\n\\t#endif\\n#endif\\n\";\n\nvar envmap_pars_fragment = \"#if defined( USE_ENVMAP ) || defined( PHYSICAL )\\n\\tuniform float reflectivity;\\n\\tuniform float envMapIntensity;\\n#endif\\n#ifdef USE_ENVMAP\\n\\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\\n\\t\\tvarying vec3 vWorldPosition;\\n\\t#endif\\n\\t#ifdef ENVMAP_TYPE_CUBE\\n\\t\\tuniform samplerCube envMap;\\n\\t#else\\n\\t\\tuniform sampler2D envMap;\\n\\t#endif\\n\\tuniform float flipEnvMap;\\n\\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\\n\\t\\tuniform float refractionRatio;\\n\\t#else\\n\\t\\tvarying vec3 vReflect;\\n\\t#endif\\n#endif\\n\";\n\nvar envmap_pars_vertex = \"#ifdef USE_ENVMAP\\n\\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\\n\\t\\tvarying vec3 vWorldPosition;\\n\\t#else\\n\\t\\tvarying vec3 vReflect;\\n\\t\\tuniform float refractionRatio;\\n\\t#endif\\n#endif\\n\";\n\nvar envmap_vertex = \"#ifdef USE_ENVMAP\\n\\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\\n\\t\\tvWorldPosition = worldPosition.xyz;\\n\\t#else\\n\\t\\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\\n\\t\\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\\n\\t\\t#ifdef ENVMAP_MODE_REFLECTION\\n\\t\\t\\tvReflect = reflect( cameraToVertex, worldNormal );\\n\\t\\t#else\\n\\t\\t\\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\\n\\t\\t#endif\\n\\t#endif\\n#endif\\n\";\n\nvar fog_vertex = \"\\n#ifdef USE_FOG\\nfogDepth = -mvPosition.z;\\n#endif\";\n\nvar fog_pars_vertex = \"#ifdef USE_FOG\\n varying float fogDepth;\\n#endif\\n\";\n\nvar fog_fragment = \"#ifdef USE_FOG\\n\\t#ifdef FOG_EXP2\\n\\t\\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );\\n\\t#else\\n\\t\\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\\n\\t#endif\\n\\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\\n#endif\\n\";\n\nvar fog_pars_fragment = \"#ifdef USE_FOG\\n\\tuniform vec3 fogColor;\\n\\tvarying float fogDepth;\\n\\t#ifdef FOG_EXP2\\n\\t\\tuniform float fogDensity;\\n\\t#else\\n\\t\\tuniform float fogNear;\\n\\t\\tuniform float fogFar;\\n\\t#endif\\n#endif\\n\";\n\nvar gradientmap_pars_fragment = \"#ifdef TOON\\n\\tuniform sampler2D gradientMap;\\n\\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\\n\\t\\tfloat dotNL = dot( normal, lightDirection );\\n\\t\\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\\n\\t\\t#ifdef USE_GRADIENTMAP\\n\\t\\t\\treturn texture2D( gradientMap, coord ).rgb;\\n\\t\\t#else\\n\\t\\t\\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\\n\\t\\t#endif\\n\\t}\\n#endif\\n\";\n\nvar lightmap_fragment = \"#ifdef USE_LIGHTMAP\\n\\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\\n#endif\\n\";\n\nvar lightmap_pars_fragment = \"#ifdef USE_LIGHTMAP\\n\\tuniform sampler2D lightMap;\\n\\tuniform float lightMapIntensity;\\n#endif\";\n\nvar lights_lambert_vertex = \"vec3 diffuse = vec3( 1.0 );\\nGeometricContext geometry;\\ngeometry.position = mvPosition.xyz;\\ngeometry.normal = normalize( transformedNormal );\\ngeometry.viewDir = normalize( -mvPosition.xyz );\\nGeometricContext backGeometry;\\nbackGeometry.position = geometry.position;\\nbackGeometry.normal = -geometry.normal;\\nbackGeometry.viewDir = geometry.viewDir;\\nvLightFront = vec3( 0.0 );\\n#ifdef DOUBLE_SIDED\\n\\tvLightBack = vec3( 0.0 );\\n#endif\\nIncidentLight directLight;\\nfloat dotNL;\\nvec3 directLightColor_Diffuse;\\n#if NUM_POINT_LIGHTS > 0\\n\\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\\n\\t\\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\\n\\t\\tdotNL = dot( geometry.normal, directLight.direction );\\n\\t\\tdirectLightColor_Diffuse = PI * directLight.color;\\n\\t\\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\\n\\t\\t#ifdef DOUBLE_SIDED\\n\\t\\t\\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\\n\\t\\t#endif\\n\\t}\\n#endif\\n#if NUM_SPOT_LIGHTS > 0\\n\\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\\n\\t\\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\\n\\t\\tdotNL = dot( geometry.normal, directLight.direction );\\n\\t\\tdirectLightColor_Diffuse = PI * directLight.color;\\n\\t\\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\\n\\t\\t#ifdef DOUBLE_SIDED\\n\\t\\t\\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\\n\\t\\t#endif\\n\\t}\\n#endif\\n#if NUM_DIR_LIGHTS > 0\\n\\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\\n\\t\\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\\n\\t\\tdotNL = dot( geometry.normal, directLight.direction );\\n\\t\\tdirectLightColor_Diffuse = PI * directLight.color;\\n\\t\\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\\n\\t\\t#ifdef DOUBLE_SIDED\\n\\t\\t\\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\\n\\t\\t#endif\\n\\t}\\n#endif\\n#if NUM_HEMI_LIGHTS > 0\\n\\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\\n\\t\\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\\n\\t\\t#ifdef DOUBLE_SIDED\\n\\t\\t\\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\\n\\t\\t#endif\\n\\t}\\n#endif\\n\";\n\nvar lights_pars = \"uniform vec3 ambientLightColor;\\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\\n\\tvec3 irradiance = ambientLightColor;\\n\\t#ifndef PHYSICALLY_CORRECT_LIGHTS\\n\\t\\tirradiance *= PI;\\n\\t#endif\\n\\treturn irradiance;\\n}\\n#if NUM_DIR_LIGHTS > 0\\n\\tstruct DirectionalLight {\\n\\t\\tvec3 direction;\\n\\t\\tvec3 color;\\n\\t\\tint shadow;\\n\\t\\tfloat shadowBias;\\n\\t\\tfloat shadowRadius;\\n\\t\\tvec2 shadowMapSize;\\n\\t};\\n\\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\\n\\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\\n\\t\\tdirectLight.color = directionalLight.color;\\n\\t\\tdirectLight.direction = directionalLight.direction;\\n\\t\\tdirectLight.visible = true;\\n\\t}\\n#endif\\n#if NUM_POINT_LIGHTS > 0\\n\\tstruct PointLight {\\n\\t\\tvec3 position;\\n\\t\\tvec3 color;\\n\\t\\tfloat distance;\\n\\t\\tfloat decay;\\n\\t\\tint shadow;\\n\\t\\tfloat shadowBias;\\n\\t\\tfloat shadowRadius;\\n\\t\\tvec2 shadowMapSize;\\n\\t};\\n\\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\\n\\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\\n\\t\\tvec3 lVector = pointLight.position - geometry.position;\\n\\t\\tdirectLight.direction = normalize( lVector );\\n\\t\\tfloat lightDistance = length( lVector );\\n\\t\\tdirectLight.color = pointLight.color;\\n\\t\\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\\n\\t\\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\\n\\t}\\n#endif\\n#if NUM_SPOT_LIGHTS > 0\\n\\tstruct SpotLight {\\n\\t\\tvec3 position;\\n\\t\\tvec3 direction;\\n\\t\\tvec3 color;\\n\\t\\tfloat distance;\\n\\t\\tfloat decay;\\n\\t\\tfloat coneCos;\\n\\t\\tfloat penumbraCos;\\n\\t\\tint shadow;\\n\\t\\tfloat shadowBias;\\n\\t\\tfloat shadowRadius;\\n\\t\\tvec2 shadowMapSize;\\n\\t};\\n\\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\\n\\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\\n\\t\\tvec3 lVector = spotLight.position - geometry.position;\\n\\t\\tdirectLight.direction = normalize( lVector );\\n\\t\\tfloat lightDistance = length( lVector );\\n\\t\\tfloat angleCos = dot( directLight.direction, spotLight.direction );\\n\\t\\tif ( angleCos > spotLight.coneCos ) {\\n\\t\\t\\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\\n\\t\\t\\tdirectLight.color = spotLight.color;\\n\\t\\t\\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\\n\\t\\t\\tdirectLight.visible = true;\\n\\t\\t} else {\\n\\t\\t\\tdirectLight.color = vec3( 0.0 );\\n\\t\\t\\tdirectLight.visible = false;\\n\\t\\t}\\n\\t}\\n#endif\\n#if NUM_RECT_AREA_LIGHTS > 0\\n\\tstruct RectAreaLight {\\n\\t\\tvec3 color;\\n\\t\\tvec3 position;\\n\\t\\tvec3 halfWidth;\\n\\t\\tvec3 halfHeight;\\n\\t};\\n\\tuniform sampler2D ltcMat;\\tuniform sampler2D ltcMag;\\n\\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\\n#endif\\n#if NUM_HEMI_LIGHTS > 0\\n\\tstruct HemisphereLight {\\n\\t\\tvec3 direction;\\n\\t\\tvec3 skyColor;\\n\\t\\tvec3 groundColor;\\n\\t};\\n\\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\\n\\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\\n\\t\\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\\n\\t\\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\\n\\t\\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\\n\\t\\t#ifndef PHYSICALLY_CORRECT_LIGHTS\\n\\t\\t\\tirradiance *= PI;\\n\\t\\t#endif\\n\\t\\treturn irradiance;\\n\\t}\\n#endif\\n#if defined( USE_ENVMAP ) && defined( PHYSICAL )\\n\\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\\n\\t\\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\\n\\t\\t#ifdef ENVMAP_TYPE_CUBE\\n\\t\\t\\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\\n\\t\\t\\t#ifdef TEXTURE_LOD_EXT\\n\\t\\t\\t\\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\\n\\t\\t\\t#else\\n\\t\\t\\t\\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\\n\\t\\t\\t#endif\\n\\t\\t\\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\\n\\t\\t#elif defined( ENVMAP_TYPE_CUBE_UV )\\n\\t\\t\\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\\n\\t\\t\\tvec4 envMapColor = textureCubeUV( queryVec, 1.0 );\\n\\t\\t#else\\n\\t\\t\\tvec4 envMapColor = vec4( 0.0 );\\n\\t\\t#endif\\n\\t\\treturn PI * envMapColor.rgb * envMapIntensity;\\n\\t}\\n\\tfloat getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {\\n\\t\\tfloat maxMIPLevelScalar = float( maxMIPLevel );\\n\\t\\tfloat desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\\n\\t\\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\\n\\t}\\n\\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\\n\\t\\t#ifdef ENVMAP_MODE_REFLECTION\\n\\t\\t\\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\\n\\t\\t#else\\n\\t\\t\\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\\n\\t\\t#endif\\n\\t\\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\\n\\t\\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );\\n\\t\\t#ifdef ENVMAP_TYPE_CUBE\\n\\t\\t\\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\\n\\t\\t\\t#ifdef TEXTURE_LOD_EXT\\n\\t\\t\\t\\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\\n\\t\\t\\t#else\\n\\t\\t\\t\\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\\n\\t\\t\\t#endif\\n\\t\\t\\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\\n\\t\\t#elif defined( ENVMAP_TYPE_CUBE_UV )\\n\\t\\t\\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\\n\\t\\t\\tvec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent));\\n\\t\\t#elif defined( ENVMAP_TYPE_EQUIREC )\\n\\t\\t\\tvec2 sampleUV;\\n\\t\\t\\tsampleUV.y = saturate( reflectVec.y * 0.5 + 0.5 );\\n\\t\\t\\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\\n\\t\\t\\t#ifdef TEXTURE_LOD_EXT\\n\\t\\t\\t\\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\\n\\t\\t\\t#else\\n\\t\\t\\t\\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\\n\\t\\t\\t#endif\\n\\t\\t\\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\\n\\t\\t#elif defined( ENVMAP_TYPE_SPHERE )\\n\\t\\t\\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\\n\\t\\t\\t#ifdef TEXTURE_LOD_EXT\\n\\t\\t\\t\\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\\n\\t\\t\\t#else\\n\\t\\t\\t\\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\\n\\t\\t\\t#endif\\n\\t\\t\\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\\n\\t\\t#endif\\n\\t\\treturn envMapColor.rgb * envMapIntensity;\\n\\t}\\n#endif\\n\";\n\nvar lights_phong_fragment = \"BlinnPhongMaterial material;\\nmaterial.diffuseColor = diffuseColor.rgb;\\nmaterial.specularColor = specular;\\nmaterial.specularShininess = shininess;\\nmaterial.specularStrength = specularStrength;\\n\";\n\nvar lights_phong_pars_fragment = \"varying vec3 vViewPosition;\\n#ifndef FLAT_SHADED\\n\\tvarying vec3 vNormal;\\n#endif\\nstruct BlinnPhongMaterial {\\n\\tvec3\\tdiffuseColor;\\n\\tvec3\\tspecularColor;\\n\\tfloat\\tspecularShininess;\\n\\tfloat\\tspecularStrength;\\n};\\n#if NUM_RECT_AREA_LIGHTS > 0\\n\\tvoid RE_Direct_RectArea_BlinnPhong( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\\n\\t\\tvec3 matDiffColor = material.diffuseColor;\\n\\t\\tvec3 matSpecColor = material.specularColor;\\n\\t\\tvec3 lightColor = rectAreaLight.color;\\n\\t\\tfloat roughness = BlinnExponentToGGXRoughness( material.specularShininess );\\n\\t\\tvec3 spec = Rect_Area_Light_Specular_Reflectance(\\n\\t\\t\\t\\tgeometry,\\n\\t\\t\\t\\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight,\\n\\t\\t\\t\\troughness,\\n\\t\\t\\t\\tltcMat, ltcMag );\\n\\t\\tvec3 diff = Rect_Area_Light_Diffuse_Reflectance(\\n\\t\\t\\t\\tgeometry,\\n\\t\\t\\t\\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight );\\n\\t\\treflectedLight.directSpecular += lightColor * matSpecColor * spec / PI2;\\n\\t\\treflectedLight.directDiffuse += lightColor * matDiffColor * diff / PI2;\\n\\t}\\n#endif\\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\\n\\t#ifdef TOON\\n\\t\\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\\n\\t#else\\n\\t\\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\\n\\t\\tvec3 irradiance = dotNL * directLight.color;\\n\\t#endif\\n\\t#ifndef PHYSICALLY_CORRECT_LIGHTS\\n\\t\\tirradiance *= PI;\\n\\t#endif\\n\\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\\n\\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\\n}\\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\\n\\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\\n}\\n#define RE_Direct\\t\\t\\t\\tRE_Direct_BlinnPhong\\n#define RE_Direct_RectArea\\t\\tRE_Direct_RectArea_BlinnPhong\\n#define RE_IndirectDiffuse\\t\\tRE_IndirectDiffuse_BlinnPhong\\n#define Material_LightProbeLOD( material )\\t(0)\\n\";\n\nvar lights_physical_fragment = \"PhysicalMaterial material;\\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\\n#ifdef STANDARD\\n\\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\\n#else\\n\\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\\n\\tmaterial.clearCoat = saturate( clearCoat );\\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\\n#endif\\n\";\n\nvar lights_physical_pars_fragment = \"struct PhysicalMaterial {\\n\\tvec3\\tdiffuseColor;\\n\\tfloat\\tspecularRoughness;\\n\\tvec3\\tspecularColor;\\n\\t#ifndef STANDARD\\n\\t\\tfloat clearCoat;\\n\\t\\tfloat clearCoatRoughness;\\n\\t#endif\\n};\\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\\nfloat clearCoatDHRApprox( const in float roughness, const in float dotNL ) {\\n\\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\\n}\\n#if NUM_RECT_AREA_LIGHTS > 0\\n\\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\\n\\t\\tvec3 matDiffColor = material.diffuseColor;\\n\\t\\tvec3 matSpecColor = material.specularColor;\\n\\t\\tvec3 lightColor = rectAreaLight.color;\\n\\t\\tfloat roughness = material.specularRoughness;\\n\\t\\tvec3 spec = Rect_Area_Light_Specular_Reflectance(\\n\\t\\t\\t\\tgeometry,\\n\\t\\t\\t\\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight,\\n\\t\\t\\t\\troughness,\\n\\t\\t\\t\\tltcMat, ltcMag );\\n\\t\\tvec3 diff = Rect_Area_Light_Diffuse_Reflectance(\\n\\t\\t\\t\\tgeometry,\\n\\t\\t\\t\\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight );\\n\\t\\treflectedLight.directSpecular += lightColor * matSpecColor * spec;\\n\\t\\treflectedLight.directDiffuse += lightColor * matDiffColor * diff;\\n\\t}\\n#endif\\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\\n\\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\\n\\tvec3 irradiance = dotNL * directLight.color;\\n\\t#ifndef PHYSICALLY_CORRECT_LIGHTS\\n\\t\\tirradiance *= PI;\\n\\t#endif\\n\\t#ifndef STANDARD\\n\\t\\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\\n\\t#else\\n\\t\\tfloat clearCoatDHR = 0.0;\\n\\t#endif\\n\\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\\n\\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\\n\\t#ifndef STANDARD\\n\\t\\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\\n\\t#endif\\n}\\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\\n\\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\\n}\\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\\n\\t#ifndef STANDARD\\n\\t\\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\\n\\t\\tfloat dotNL = dotNV;\\n\\t\\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\\n\\t#else\\n\\t\\tfloat clearCoatDHR = 0.0;\\n\\t#endif\\n\\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\\n\\t#ifndef STANDARD\\n\\t\\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\\n\\t#endif\\n}\\n#define RE_Direct\\t\\t\\t\\tRE_Direct_Physical\\n#define RE_Direct_RectArea\\t\\tRE_Direct_RectArea_Physical\\n#define RE_IndirectDiffuse\\t\\tRE_IndirectDiffuse_Physical\\n#define RE_IndirectSpecular\\t\\tRE_IndirectSpecular_Physical\\n#define Material_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.specularRoughness )\\n#define Material_ClearCoat_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\\n\\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\\n}\\n\";\n\nvar lights_template = \"\\nGeometricContext geometry;\\ngeometry.position = - vViewPosition;\\ngeometry.normal = normal;\\ngeometry.viewDir = normalize( vViewPosition );\\nIncidentLight directLight;\\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\\n\\tPointLight pointLight;\\n\\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\\n\\t\\tpointLight = pointLights[ i ];\\n\\t\\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\\n\\t\\t#ifdef USE_SHADOWMAP\\n\\t\\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\\n\\t\\t#endif\\n\\t\\tRE_Direct( directLight, geometry, material, reflectedLight );\\n\\t}\\n#endif\\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\\n\\tSpotLight spotLight;\\n\\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\\n\\t\\tspotLight = spotLights[ i ];\\n\\t\\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\\n\\t\\t#ifdef USE_SHADOWMAP\\n\\t\\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\\n\\t\\t#endif\\n\\t\\tRE_Direct( directLight, geometry, material, reflectedLight );\\n\\t}\\n#endif\\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\\n\\tDirectionalLight directionalLight;\\n\\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\\n\\t\\tdirectionalLight = directionalLights[ i ];\\n\\t\\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\\n\\t\\t#ifdef USE_SHADOWMAP\\n\\t\\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\\n\\t\\t#endif\\n\\t\\tRE_Direct( directLight, geometry, material, reflectedLight );\\n\\t}\\n#endif\\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\\n\\tRectAreaLight rectAreaLight;\\n\\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\\n\\t\\trectAreaLight = rectAreaLights[ i ];\\n\\t\\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\\n\\t}\\n#endif\\n#if defined( RE_IndirectDiffuse )\\n\\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\\n\\t#ifdef USE_LIGHTMAP\\n\\t\\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\\n\\t\\t#ifndef PHYSICALLY_CORRECT_LIGHTS\\n\\t\\t\\tlightMapIrradiance *= PI;\\n\\t\\t#endif\\n\\t\\tirradiance += lightMapIrradiance;\\n\\t#endif\\n\\t#if ( NUM_HEMI_LIGHTS > 0 )\\n\\t\\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\\n\\t\\t\\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\\n\\t\\t}\\n\\t#endif\\n\\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\\n\\t\\tirradiance += getLightProbeIndirectIrradiance( geometry, 8 );\\n\\t#endif\\n\\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\\n#endif\\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\\n\\tvec3 radiance = getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), 8 );\\n\\t#ifndef STANDARD\\n\\t\\tvec3 clearCoatRadiance = getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), 8 );\\n\\t#else\\n\\t\\tvec3 clearCoatRadiance = vec3( 0.0 );\\n\\t#endif\\n\\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\\n#endif\\n\";\n\nvar logdepthbuf_fragment = \"#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\\n\\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\\n#endif\";\n\nvar logdepthbuf_pars_fragment = \"#ifdef USE_LOGDEPTHBUF\\n\\tuniform float logDepthBufFC;\\n\\t#ifdef USE_LOGDEPTHBUF_EXT\\n\\t\\tvarying float vFragDepth;\\n\\t#endif\\n#endif\\n\";\n\nvar logdepthbuf_pars_vertex = \"#ifdef USE_LOGDEPTHBUF\\n\\t#ifdef USE_LOGDEPTHBUF_EXT\\n\\t\\tvarying float vFragDepth;\\n\\t#endif\\n\\tuniform float logDepthBufFC;\\n#endif\";\n\nvar logdepthbuf_vertex = \"#ifdef USE_LOGDEPTHBUF\\n\\tgl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\\n\\t#ifdef USE_LOGDEPTHBUF_EXT\\n\\t\\tvFragDepth = 1.0 + gl_Position.w;\\n\\t#else\\n\\t\\tgl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\\n\\t#endif\\n#endif\\n\";\n\nvar map_fragment = \"#ifdef USE_MAP\\n\\tvec4 texelColor = texture2D( map, vUv );\\n\\ttexelColor = mapTexelToLinear( texelColor );\\n\\tdiffuseColor *= texelColor;\\n#endif\\n\";\n\nvar map_pars_fragment = \"#ifdef USE_MAP\\n\\tuniform sampler2D map;\\n#endif\\n\";\n\nvar map_particle_fragment = \"#ifdef USE_MAP\\n\\tvec4 mapTexel = texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\\n\\tdiffuseColor *= mapTexelToLinear( mapTexel );\\n#endif\\n\";\n\nvar map_particle_pars_fragment = \"#ifdef USE_MAP\\n\\tuniform vec4 offsetRepeat;\\n\\tuniform sampler2D map;\\n#endif\\n\";\n\nvar metalnessmap_fragment = \"float metalnessFactor = metalness;\\n#ifdef USE_METALNESSMAP\\n\\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\\n\\tmetalnessFactor *= texelMetalness.r;\\n#endif\\n\";\n\nvar metalnessmap_pars_fragment = \"#ifdef USE_METALNESSMAP\\n\\tuniform sampler2D metalnessMap;\\n#endif\";\n\nvar morphnormal_vertex = \"#ifdef USE_MORPHNORMALS\\n\\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\\n\\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\\n\\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\\n\\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\\n#endif\\n\";\n\nvar morphtarget_pars_vertex = \"#ifdef USE_MORPHTARGETS\\n\\t#ifndef USE_MORPHNORMALS\\n\\tuniform float morphTargetInfluences[ 8 ];\\n\\t#else\\n\\tuniform float morphTargetInfluences[ 4 ];\\n\\t#endif\\n#endif\";\n\nvar morphtarget_vertex = \"#ifdef USE_MORPHTARGETS\\n\\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\\n\\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\\n\\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\\n\\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\\n\\t#ifndef USE_MORPHNORMALS\\n\\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\\n\\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\\n\\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\\n\\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\\n\\t#endif\\n#endif\\n\";\n\nvar normal_flip = \"#ifdef DOUBLE_SIDED\\n\\tfloat flipNormal = ( float( gl_FrontFacing ) * 2.0 - 1.0 );\\n#else\\n\\tfloat flipNormal = 1.0;\\n#endif\\n\";\n\nvar normal_fragment = \"#ifdef FLAT_SHADED\\n\\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\\n\\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\\n\\tvec3 normal = normalize( cross( fdx, fdy ) );\\n#else\\n\\tvec3 normal = normalize( vNormal ) * flipNormal;\\n#endif\\n#ifdef USE_NORMALMAP\\n\\tnormal = perturbNormal2Arb( -vViewPosition, normal );\\n#elif defined( USE_BUMPMAP )\\n\\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\\n#endif\\n\";\n\nvar normalmap_pars_fragment = \"#ifdef USE_NORMALMAP\\n\\tuniform sampler2D normalMap;\\n\\tuniform vec2 normalScale;\\n\\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\\n\\t\\tvec3 q0 = dFdx( eye_pos.xyz );\\n\\t\\tvec3 q1 = dFdy( eye_pos.xyz );\\n\\t\\tvec2 st0 = dFdx( vUv.st );\\n\\t\\tvec2 st1 = dFdy( vUv.st );\\n\\t\\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\\n\\t\\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\\n\\t\\tvec3 N = normalize( surf_norm );\\n\\t\\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\\n\\t\\tmapN.xy = normalScale * mapN.xy;\\n\\t\\tmat3 tsn = mat3( S, T, N );\\n\\t\\treturn normalize( tsn * mapN );\\n\\t}\\n#endif\\n\";\n\nvar packing = \"vec3 packNormalToRGB( const in vec3 normal ) {\\n\\treturn normalize( normal ) * 0.5 + 0.5;\\n}\\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\\n\\treturn 1.0 - 2.0 * rgb.xyz;\\n}\\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\\nconst float ShiftRight8 = 1. / 256.;\\nvec4 packDepthToRGBA( const in float v ) {\\n\\tvec4 r = vec4( fract( v * PackFactors ), v );\\n\\tr.yzw -= r.xyz * ShiftRight8;\\treturn r * PackUpscale;\\n}\\nfloat unpackRGBAToDepth( const in vec4 v ) {\\n\\treturn dot( v, UnpackFactors );\\n}\\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\\n\\treturn ( viewZ + near ) / ( near - far );\\n}\\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\\n\\treturn linearClipZ * ( near - far ) - near;\\n}\\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\\n\\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\\n}\\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\\n\\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\\n}\\n\";\n\nvar premultiplied_alpha_fragment = \"#ifdef PREMULTIPLIED_ALPHA\\n\\tgl_FragColor.rgb *= gl_FragColor.a;\\n#endif\\n\";\n\nvar project_vertex = \"#ifdef USE_SKINNING\\n\\tvec4 mvPosition = modelViewMatrix * skinned;\\n#else\\n\\tvec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\\n#endif\\ngl_Position = projectionMatrix * mvPosition;\\n\";\n\nvar roughnessmap_fragment = \"float roughnessFactor = roughness;\\n#ifdef USE_ROUGHNESSMAP\\n\\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\\n\\troughnessFactor *= texelRoughness.r;\\n#endif\\n\";\n\nvar roughnessmap_pars_fragment = \"#ifdef USE_ROUGHNESSMAP\\n\\tuniform sampler2D roughnessMap;\\n#endif\";\n\nvar shadowmap_pars_fragment = \"#ifdef USE_SHADOWMAP\\n\\t#if NUM_DIR_LIGHTS > 0\\n\\t\\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\\n\\t\\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\\n\\t#endif\\n\\t#if NUM_SPOT_LIGHTS > 0\\n\\t\\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\\n\\t\\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\\n\\t#endif\\n\\t#if NUM_POINT_LIGHTS > 0\\n\\t\\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\\n\\t\\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\\n\\t#endif\\n\\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\\n\\t\\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\\n\\t}\\n\\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\\n\\t\\tconst vec2 offset = vec2( 0.0, 1.0 );\\n\\t\\tvec2 texelSize = vec2( 1.0 ) / size;\\n\\t\\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\\n\\t\\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\\n\\t\\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\\n\\t\\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\\n\\t\\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\\n\\t\\tvec2 f = fract( uv * size + 0.5 );\\n\\t\\tfloat a = mix( lb, lt, f.y );\\n\\t\\tfloat b = mix( rb, rt, f.y );\\n\\t\\tfloat c = mix( a, b, f.x );\\n\\t\\treturn c;\\n\\t}\\n\\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\\n\\t\\tshadowCoord.xyz /= shadowCoord.w;\\n\\t\\tshadowCoord.z += shadowBias;\\n\\t\\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\\n\\t\\tbool inFrustum = all( inFrustumVec );\\n\\t\\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\\n\\t\\tbool frustumTest = all( frustumTestVec );\\n\\t\\tif ( frustumTest ) {\\n\\t\\t#if defined( SHADOWMAP_TYPE_PCF )\\n\\t\\t\\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\\n\\t\\t\\tfloat dx0 = - texelSize.x * shadowRadius;\\n\\t\\t\\tfloat dy0 = - texelSize.y * shadowRadius;\\n\\t\\t\\tfloat dx1 = + texelSize.x * shadowRadius;\\n\\t\\t\\tfloat dy1 = + texelSize.y * shadowRadius;\\n\\t\\t\\treturn (\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\\n\\t\\t\\t) * ( 1.0 / 9.0 );\\n\\t\\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\\n\\t\\t\\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\\n\\t\\t\\tfloat dx0 = - texelSize.x * shadowRadius;\\n\\t\\t\\tfloat dy0 = - texelSize.y * shadowRadius;\\n\\t\\t\\tfloat dx1 = + texelSize.x * shadowRadius;\\n\\t\\t\\tfloat dy1 = + texelSize.y * shadowRadius;\\n\\t\\t\\treturn (\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\\n\\t\\t\\t) * ( 1.0 / 9.0 );\\n\\t\\t#else\\n\\t\\t\\treturn texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\\n\\t\\t#endif\\n\\t\\t}\\n\\t\\treturn 1.0;\\n\\t}\\n\\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\\n\\t\\tvec3 absV = abs( v );\\n\\t\\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\\n\\t\\tabsV *= scaleToCube;\\n\\t\\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\\n\\t\\tvec2 planar = v.xy;\\n\\t\\tfloat almostATexel = 1.5 * texelSizeY;\\n\\t\\tfloat almostOne = 1.0 - almostATexel;\\n\\t\\tif ( absV.z >= almostOne ) {\\n\\t\\t\\tif ( v.z > 0.0 )\\n\\t\\t\\t\\tplanar.x = 4.0 - v.x;\\n\\t\\t} else if ( absV.x >= almostOne ) {\\n\\t\\t\\tfloat signX = sign( v.x );\\n\\t\\t\\tplanar.x = v.z * signX + 2.0 * signX;\\n\\t\\t} else if ( absV.y >= almostOne ) {\\n\\t\\t\\tfloat signY = sign( v.y );\\n\\t\\t\\tplanar.x = v.x + 2.0 * signY + 2.0;\\n\\t\\t\\tplanar.y = v.z * signY - 2.0;\\n\\t\\t}\\n\\t\\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\\n\\t}\\n\\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\\n\\t\\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\\n\\t\\tvec3 lightToPosition = shadowCoord.xyz;\\n\\t\\tvec3 bd3D = normalize( lightToPosition );\\n\\t\\tfloat dp = ( length( lightToPosition ) - shadowBias ) / 1000.0;\\n\\t\\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )\\n\\t\\t\\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\\n\\t\\t\\treturn (\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\\n\\t\\t\\t) * ( 1.0 / 9.0 );\\n\\t\\t#else\\n\\t\\t\\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\\n\\t\\t#endif\\n\\t}\\n#endif\\n\";\n\nvar shadowmap_pars_vertex = \"#ifdef USE_SHADOWMAP\\n\\t#if NUM_DIR_LIGHTS > 0\\n\\t\\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\\n\\t\\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\\n\\t#endif\\n\\t#if NUM_SPOT_LIGHTS > 0\\n\\t\\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\\n\\t\\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\\n\\t#endif\\n\\t#if NUM_POINT_LIGHTS > 0\\n\\t\\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\\n\\t\\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\\n\\t#endif\\n#endif\\n\";\n\nvar shadowmap_vertex = \"#ifdef USE_SHADOWMAP\\n\\t#if NUM_DIR_LIGHTS > 0\\n\\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\\n\\t\\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\\n\\t}\\n\\t#endif\\n\\t#if NUM_SPOT_LIGHTS > 0\\n\\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\\n\\t\\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\\n\\t}\\n\\t#endif\\n\\t#if NUM_POINT_LIGHTS > 0\\n\\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\\n\\t\\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\\n\\t}\\n\\t#endif\\n#endif\\n\";\n\nvar shadowmask_pars_fragment = \"float getShadowMask() {\\n\\tfloat shadow = 1.0;\\n\\t#ifdef USE_SHADOWMAP\\n\\t#if NUM_DIR_LIGHTS > 0\\n\\tDirectionalLight directionalLight;\\n\\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\\n\\t\\tdirectionalLight = directionalLights[ i ];\\n\\t\\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\\n\\t}\\n\\t#endif\\n\\t#if NUM_SPOT_LIGHTS > 0\\n\\tSpotLight spotLight;\\n\\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\\n\\t\\tspotLight = spotLights[ i ];\\n\\t\\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\\n\\t}\\n\\t#endif\\n\\t#if NUM_POINT_LIGHTS > 0\\n\\tPointLight pointLight;\\n\\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\\n\\t\\tpointLight = pointLights[ i ];\\n\\t\\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\\n\\t}\\n\\t#endif\\n\\t#endif\\n\\treturn shadow;\\n}\\n\";\n\nvar skinbase_vertex = \"#ifdef USE_SKINNING\\n\\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\\n\\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\\n\\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\\n\\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\\n#endif\";\n\nvar skinning_pars_vertex = \"#ifdef USE_SKINNING\\n\\tuniform mat4 bindMatrix;\\n\\tuniform mat4 bindMatrixInverse;\\n\\t#ifdef BONE_TEXTURE\\n\\t\\tuniform sampler2D boneTexture;\\n\\t\\tuniform int boneTextureWidth;\\n\\t\\tuniform int boneTextureHeight;\\n\\t\\tmat4 getBoneMatrix( const in float i ) {\\n\\t\\t\\tfloat j = i * 4.0;\\n\\t\\t\\tfloat x = mod( j, float( boneTextureWidth ) );\\n\\t\\t\\tfloat y = floor( j / float( boneTextureWidth ) );\\n\\t\\t\\tfloat dx = 1.0 / float( boneTextureWidth );\\n\\t\\t\\tfloat dy = 1.0 / float( boneTextureHeight );\\n\\t\\t\\ty = dy * ( y + 0.5 );\\n\\t\\t\\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\\n\\t\\t\\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\\n\\t\\t\\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\\n\\t\\t\\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\\n\\t\\t\\tmat4 bone = mat4( v1, v2, v3, v4 );\\n\\t\\t\\treturn bone;\\n\\t\\t}\\n\\t#else\\n\\t\\tuniform mat4 boneMatrices[ MAX_BONES ];\\n\\t\\tmat4 getBoneMatrix( const in float i ) {\\n\\t\\t\\tmat4 bone = boneMatrices[ int(i) ];\\n\\t\\t\\treturn bone;\\n\\t\\t}\\n\\t#endif\\n#endif\\n\";\n\nvar skinning_vertex = \"#ifdef USE_SKINNING\\n\\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\\n\\tvec4 skinned = vec4( 0.0 );\\n\\tskinned += boneMatX * skinVertex * skinWeight.x;\\n\\tskinned += boneMatY * skinVertex * skinWeight.y;\\n\\tskinned += boneMatZ * skinVertex * skinWeight.z;\\n\\tskinned += boneMatW * skinVertex * skinWeight.w;\\n\\tskinned = bindMatrixInverse * skinned;\\n#endif\\n\";\n\nvar skinnormal_vertex = \"#ifdef USE_SKINNING\\n\\tmat4 skinMatrix = mat4( 0.0 );\\n\\tskinMatrix += skinWeight.x * boneMatX;\\n\\tskinMatrix += skinWeight.y * boneMatY;\\n\\tskinMatrix += skinWeight.z * boneMatZ;\\n\\tskinMatrix += skinWeight.w * boneMatW;\\n\\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\\n\\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\\n#endif\\n\";\n\nvar specularmap_fragment = \"float specularStrength;\\n#ifdef USE_SPECULARMAP\\n\\tvec4 texelSpecular = texture2D( specularMap, vUv );\\n\\tspecularStrength = texelSpecular.r;\\n#else\\n\\tspecularStrength = 1.0;\\n#endif\";\n\nvar specularmap_pars_fragment = \"#ifdef USE_SPECULARMAP\\n\\tuniform sampler2D specularMap;\\n#endif\";\n\nvar tonemapping_fragment = \"#if defined( TONE_MAPPING )\\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\\n#endif\\n\";\n\nvar tonemapping_pars_fragment = \"#define saturate(a) clamp( a, 0.0, 1.0 )\\nuniform float toneMappingExposure;\\nuniform float toneMappingWhitePoint;\\nvec3 LinearToneMapping( vec3 color ) {\\n\\treturn toneMappingExposure * color;\\n}\\nvec3 ReinhardToneMapping( vec3 color ) {\\n\\tcolor *= toneMappingExposure;\\n\\treturn saturate( color / ( vec3( 1.0 ) + color ) );\\n}\\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\\nvec3 Uncharted2ToneMapping( vec3 color ) {\\n\\tcolor *= toneMappingExposure;\\n\\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\\n}\\nvec3 OptimizedCineonToneMapping( vec3 color ) {\\n\\tcolor *= toneMappingExposure;\\n\\tcolor = max( vec3( 0.0 ), color - 0.004 );\\n\\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\\n}\\n\";\n\nvar uv_pars_fragment = \"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\\n\\tvarying vec2 vUv;\\n#endif\";\n\nvar uv_pars_vertex = \"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\\n\\tvarying vec2 vUv;\\n\\tuniform vec4 offsetRepeat;\\n#endif\\n\";\n\nvar uv_vertex = \"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\\n\\tvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\\n#endif\";\n\nvar uv2_pars_fragment = \"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\\n\\tvarying vec2 vUv2;\\n#endif\";\n\nvar uv2_pars_vertex = \"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\\n\\tattribute vec2 uv2;\\n\\tvarying vec2 vUv2;\\n#endif\";\n\nvar uv2_vertex = \"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\\n\\tvUv2 = uv2;\\n#endif\";\n\nvar worldpos_vertex = \"#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( PHYSICAL ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\\n\\t#ifdef USE_SKINNING\\n\\t\\tvec4 worldPosition = modelMatrix * skinned;\\n\\t#else\\n\\t\\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\\n\\t#endif\\n#endif\\n\";\n\nvar cube_frag = \"uniform samplerCube tCube;\\nuniform float tFlip;\\nuniform float opacity;\\nvarying vec3 vWorldPosition;\\n#include \\nvoid main() {\\n\\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\\n\\tgl_FragColor.a *= opacity;\\n}\\n\";\n\nvar cube_vert = \"varying vec3 vWorldPosition;\\n#include \\nvoid main() {\\n\\tvWorldPosition = transformDirection( position, modelMatrix );\\n\\t#include \\n\\t#include \\n}\\n\";\n\nvar depth_frag = \"#if DEPTH_PACKING == 3200\\n\\tuniform float opacity;\\n#endif\\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\t#include \\n\\tvec4 diffuseColor = vec4( 1.0 );\\n\\t#if DEPTH_PACKING == 3200\\n\\t\\tdiffuseColor.a = opacity;\\n\\t#endif\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#if DEPTH_PACKING == 3200\\n\\t\\tgl_FragColor = vec4( vec3( gl_FragCoord.z ), opacity );\\n\\t#elif DEPTH_PACKING == 3201\\n\\t\\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\\n\\t#endif\\n}\\n\";\n\nvar depth_vert = \"#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n}\\n\";\n\nvar distanceRGBA_frag = \"uniform vec3 lightPos;\\nvarying vec4 vWorldPosition;\\n#include \\n#include \\n#include \\nvoid main () {\\n\\t#include \\n\\tgl_FragColor = packDepthToRGBA( length( vWorldPosition.xyz - lightPos.xyz ) / 1000.0 );\\n}\\n\";\n\nvar distanceRGBA_vert = \"varying vec4 vWorldPosition;\\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\tvWorldPosition = worldPosition;\\n}\\n\";\n\nvar equirect_frag = \"uniform sampler2D tEquirect;\\nuniform float tFlip;\\nvarying vec3 vWorldPosition;\\n#include \\nvoid main() {\\n\\tvec3 direction = normalize( vWorldPosition );\\n\\tvec2 sampleUV;\\n\\tsampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );\\n\\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\\n\\tgl_FragColor = texture2D( tEquirect, sampleUV );\\n}\\n\";\n\nvar equirect_vert = \"varying vec3 vWorldPosition;\\n#include \\nvoid main() {\\n\\tvWorldPosition = transformDirection( position, modelMatrix );\\n\\t#include \\n\\t#include \\n}\\n\";\n\nvar linedashed_frag = \"uniform vec3 diffuse;\\nuniform float opacity;\\nuniform float dashSize;\\nuniform float totalSize;\\nvarying float vLineDistance;\\n#include \\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\t#include \\n\\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\\n\\t\\tdiscard;\\n\\t}\\n\\tvec3 outgoingLight = vec3( 0.0 );\\n\\tvec4 diffuseColor = vec4( diffuse, opacity );\\n\\t#include \\n\\t#include \\n\\toutgoingLight = diffuseColor.rgb;\\n\\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n}\\n\";\n\nvar linedashed_vert = \"uniform float scale;\\nattribute float lineDistance;\\nvarying float vLineDistance;\\n#include \\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\t#include \\n\\tvLineDistance = scale * lineDistance;\\n\\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\\n\\tgl_Position = projectionMatrix * mvPosition;\\n\\t#include \\n\\t#include \\n\\t#include \\n}\\n\";\n\nvar meshbasic_frag = \"uniform vec3 diffuse;\\nuniform float opacity;\\n#ifndef FLAT_SHADED\\n\\tvarying vec3 vNormal;\\n#endif\\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\t#include \\n\\tvec4 diffuseColor = vec4( diffuse, opacity );\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\\n\\t#ifdef USE_LIGHTMAP\\n\\t\\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\\n\\t#else\\n\\t\\treflectedLight.indirectDiffuse += vec3( 1.0 );\\n\\t#endif\\n\\t#include \\n\\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\\n\\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\\n\\t#include \\n\\t#include \\n\\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n}\\n\";\n\nvar meshbasic_vert = \"#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#ifdef USE_ENVMAP\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#endif\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n}\\n\";\n\nvar meshlambert_frag = \"uniform vec3 diffuse;\\nuniform vec3 emissive;\\nuniform float opacity;\\nvarying vec3 vLightFront;\\n#ifdef DOUBLE_SIDED\\n\\tvarying vec3 vLightBack;\\n#endif\\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\t#include \\n\\tvec4 diffuseColor = vec4( diffuse, opacity );\\n\\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\\n\\tvec3 totalEmissiveRadiance = emissive;\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\\n\\t#include \\n\\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\\n\\t#ifdef DOUBLE_SIDED\\n\\t\\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\\n\\t#else\\n\\t\\treflectedLight.directDiffuse = vLightFront;\\n\\t#endif\\n\\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\\n\\t#include \\n\\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\\n\\t#include \\n\\t#include \\n\\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n}\\n\";\n\nvar meshlambert_vert = \"#define LAMBERT\\nvarying vec3 vLightFront;\\n#ifdef DOUBLE_SIDED\\n\\tvarying vec3 vLightBack;\\n#endif\\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n}\\n\";\n\nvar meshphong_frag = \"#define PHONG\\nuniform vec3 diffuse;\\nuniform vec3 emissive;\\nuniform vec3 specular;\\nuniform float shininess;\\nuniform float opacity;\\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\t#include \\n\\tvec4 diffuseColor = vec4( diffuse, opacity );\\n\\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\\n\\tvec3 totalEmissiveRadiance = emissive;\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\\n\\t#include \\n\\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n}\\n\";\n\nvar meshphong_vert = \"#define PHONG\\nvarying vec3 vViewPosition;\\n#ifndef FLAT_SHADED\\n\\tvarying vec3 vNormal;\\n#endif\\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n#ifndef FLAT_SHADED\\n\\tvNormal = normalize( transformedNormal );\\n#endif\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\tvViewPosition = - mvPosition.xyz;\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n}\\n\";\n\nvar meshphysical_frag = \"#define PHYSICAL\\nuniform vec3 diffuse;\\nuniform vec3 emissive;\\nuniform float roughness;\\nuniform float metalness;\\nuniform float opacity;\\n#ifndef STANDARD\\n\\tuniform float clearCoat;\\n\\tuniform float clearCoatRoughness;\\n#endif\\nvarying vec3 vViewPosition;\\n#ifndef FLAT_SHADED\\n\\tvarying vec3 vNormal;\\n#endif\\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\t#include \\n\\tvec4 diffuseColor = vec4( diffuse, opacity );\\n\\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\\n\\tvec3 totalEmissiveRadiance = emissive;\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\\n\\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n}\\n\";\n\nvar meshphysical_vert = \"#define PHYSICAL\\nvarying vec3 vViewPosition;\\n#ifndef FLAT_SHADED\\n\\tvarying vec3 vNormal;\\n#endif\\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n#ifndef FLAT_SHADED\\n\\tvNormal = normalize( transformedNormal );\\n#endif\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\tvViewPosition = - mvPosition.xyz;\\n\\t#include \\n\\t#include \\n\\t#include \\n}\\n\";\n\nvar normal_frag = \"#define NORMAL\\nuniform float opacity;\\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\\n\\tvarying vec3 vViewPosition;\\n#endif\\n#ifndef FLAT_SHADED\\n\\tvarying vec3 vNormal;\\n#endif\\n#include \\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\t#include \\n\\t#include \\n\\t#include \\n\\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\\n}\\n\";\n\nvar normal_vert = \"#define NORMAL\\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\\n\\tvarying vec3 vViewPosition;\\n#endif\\n#ifndef FLAT_SHADED\\n\\tvarying vec3 vNormal;\\n#endif\\n#include \\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n#ifndef FLAT_SHADED\\n\\tvNormal = normalize( transformedNormal );\\n#endif\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\\n\\tvViewPosition = - mvPosition.xyz;\\n#endif\\n}\\n\";\n\nvar points_frag = \"uniform vec3 diffuse;\\nuniform float opacity;\\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\t#include \\n\\tvec3 outgoingLight = vec3( 0.0 );\\n\\tvec4 diffuseColor = vec4( diffuse, opacity );\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\toutgoingLight = diffuseColor.rgb;\\n\\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n}\\n\";\n\nvar points_vert = \"uniform float size;\\nuniform float scale;\\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#ifdef USE_SIZEATTENUATION\\n\\t\\tgl_PointSize = size * ( scale / - mvPosition.z );\\n\\t#else\\n\\t\\tgl_PointSize = size;\\n\\t#endif\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n}\\n\";\n\nvar shadow_frag = \"uniform float opacity;\\n#include \\n#include \\n#include \\n#include \\n#include \\n#include \\nvoid main() {\\n\\tgl_FragColor = vec4( 0.0, 0.0, 0.0, opacity * ( 1.0 - getShadowMask() ) );\\n}\\n\";\n\nvar shadow_vert = \"#include \\nvoid main() {\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n}\\n\";\n\nvar ShaderChunk = {\n\talphamap_fragment: alphamap_fragment,\n\talphamap_pars_fragment: alphamap_pars_fragment,\n\talphatest_fragment: alphatest_fragment,\n\taomap_fragment: aomap_fragment,\n\taomap_pars_fragment: aomap_pars_fragment,\n\tbegin_vertex: begin_vertex,\n\tbeginnormal_vertex: beginnormal_vertex,\n\tbsdfs: bsdfs,\n\tbumpmap_pars_fragment: bumpmap_pars_fragment,\n\tclipping_planes_fragment: clipping_planes_fragment,\n\tclipping_planes_pars_fragment: clipping_planes_pars_fragment,\n\tclipping_planes_pars_vertex: clipping_planes_pars_vertex,\n\tclipping_planes_vertex: clipping_planes_vertex,\n\tcolor_fragment: color_fragment,\n\tcolor_pars_fragment: color_pars_fragment,\n\tcolor_pars_vertex: color_pars_vertex,\n\tcolor_vertex: color_vertex,\n\tcommon: common,\n\tcube_uv_reflection_fragment: cube_uv_reflection_fragment,\n\tdefaultnormal_vertex: defaultnormal_vertex,\n\tdisplacementmap_pars_vertex: displacementmap_pars_vertex,\n\tdisplacementmap_vertex: displacementmap_vertex,\n\temissivemap_fragment: emissivemap_fragment,\n\temissivemap_pars_fragment: emissivemap_pars_fragment,\n\tencodings_fragment: encodings_fragment,\n\tencodings_pars_fragment: encodings_pars_fragment,\n\tenvmap_fragment: envmap_fragment,\n\tenvmap_pars_fragment: envmap_pars_fragment,\n\tenvmap_pars_vertex: envmap_pars_vertex,\n\tenvmap_vertex: envmap_vertex,\n\tfog_vertex: fog_vertex,\n\tfog_pars_vertex: fog_pars_vertex,\n\tfog_fragment: fog_fragment,\n\tfog_pars_fragment: fog_pars_fragment,\n\tgradientmap_pars_fragment: gradientmap_pars_fragment,\n\tlightmap_fragment: lightmap_fragment,\n\tlightmap_pars_fragment: lightmap_pars_fragment,\n\tlights_lambert_vertex: lights_lambert_vertex,\n\tlights_pars: lights_pars,\n\tlights_phong_fragment: lights_phong_fragment,\n\tlights_phong_pars_fragment: lights_phong_pars_fragment,\n\tlights_physical_fragment: lights_physical_fragment,\n\tlights_physical_pars_fragment: lights_physical_pars_fragment,\n\tlights_template: lights_template,\n\tlogdepthbuf_fragment: logdepthbuf_fragment,\n\tlogdepthbuf_pars_fragment: logdepthbuf_pars_fragment,\n\tlogdepthbuf_pars_vertex: logdepthbuf_pars_vertex,\n\tlogdepthbuf_vertex: logdepthbuf_vertex,\n\tmap_fragment: map_fragment,\n\tmap_pars_fragment: map_pars_fragment,\n\tmap_particle_fragment: map_particle_fragment,\n\tmap_particle_pars_fragment: map_particle_pars_fragment,\n\tmetalnessmap_fragment: metalnessmap_fragment,\n\tmetalnessmap_pars_fragment: metalnessmap_pars_fragment,\n\tmorphnormal_vertex: morphnormal_vertex,\n\tmorphtarget_pars_vertex: morphtarget_pars_vertex,\n\tmorphtarget_vertex: morphtarget_vertex,\n\tnormal_flip: normal_flip,\n\tnormal_fragment: normal_fragment,\n\tnormalmap_pars_fragment: normalmap_pars_fragment,\n\tpacking: packing,\n\tpremultiplied_alpha_fragment: premultiplied_alpha_fragment,\n\tproject_vertex: project_vertex,\n\troughnessmap_fragment: roughnessmap_fragment,\n\troughnessmap_pars_fragment: roughnessmap_pars_fragment,\n\tshadowmap_pars_fragment: shadowmap_pars_fragment,\n\tshadowmap_pars_vertex: shadowmap_pars_vertex,\n\tshadowmap_vertex: shadowmap_vertex,\n\tshadowmask_pars_fragment: shadowmask_pars_fragment,\n\tskinbase_vertex: skinbase_vertex,\n\tskinning_pars_vertex: skinning_pars_vertex,\n\tskinning_vertex: skinning_vertex,\n\tskinnormal_vertex: skinnormal_vertex,\n\tspecularmap_fragment: specularmap_fragment,\n\tspecularmap_pars_fragment: specularmap_pars_fragment,\n\ttonemapping_fragment: tonemapping_fragment,\n\ttonemapping_pars_fragment: tonemapping_pars_fragment,\n\tuv_pars_fragment: uv_pars_fragment,\n\tuv_pars_vertex: uv_pars_vertex,\n\tuv_vertex: uv_vertex,\n\tuv2_pars_fragment: uv2_pars_fragment,\n\tuv2_pars_vertex: uv2_pars_vertex,\n\tuv2_vertex: uv2_vertex,\n\tworldpos_vertex: worldpos_vertex,\n\n\tcube_frag: cube_frag,\n\tcube_vert: cube_vert,\n\tdepth_frag: depth_frag,\n\tdepth_vert: depth_vert,\n\tdistanceRGBA_frag: distanceRGBA_frag,\n\tdistanceRGBA_vert: distanceRGBA_vert,\n\tequirect_frag: equirect_frag,\n\tequirect_vert: equirect_vert,\n\tlinedashed_frag: linedashed_frag,\n\tlinedashed_vert: linedashed_vert,\n\tmeshbasic_frag: meshbasic_frag,\n\tmeshbasic_vert: meshbasic_vert,\n\tmeshlambert_frag: meshlambert_frag,\n\tmeshlambert_vert: meshlambert_vert,\n\tmeshphong_frag: meshphong_frag,\n\tmeshphong_vert: meshphong_vert,\n\tmeshphysical_frag: meshphysical_frag,\n\tmeshphysical_vert: meshphysical_vert,\n\tnormal_frag: normal_frag,\n\tnormal_vert: normal_vert,\n\tpoints_frag: points_frag,\n\tpoints_vert: points_vert,\n\tshadow_frag: shadow_frag,\n\tshadow_vert: shadow_vert\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction Color( r, g, b ) {\n\n\tif ( g === undefined && b === undefined ) {\n\n\t\t// r is THREE.Color, hex or string\n\t\treturn this.set( r );\n\n\t}\n\n\treturn this.setRGB( r, g, b );\n\n}\n\nColor.prototype = {\n\n\tconstructor: Color,\n\n\tisColor: true,\n\n\tr: 1, g: 1, b: 1,\n\n\tset: function ( value ) {\n\n\t\tif ( value && value.isColor ) {\n\n\t\t\tthis.copy( value );\n\n\t\t} else if ( typeof value === 'number' ) {\n\n\t\t\tthis.setHex( value );\n\n\t\t} else if ( typeof value === 'string' ) {\n\n\t\t\tthis.setStyle( value );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tsetScalar: function ( scalar ) {\n\n\t\tthis.r = scalar;\n\t\tthis.g = scalar;\n\t\tthis.b = scalar;\n\n\t\treturn this;\n\n\t},\n\n\tsetHex: function ( hex ) {\n\n\t\thex = Math.floor( hex );\n\n\t\tthis.r = ( hex >> 16 & 255 ) / 255;\n\t\tthis.g = ( hex >> 8 & 255 ) / 255;\n\t\tthis.b = ( hex & 255 ) / 255;\n\n\t\treturn this;\n\n\t},\n\n\tsetRGB: function ( r, g, b ) {\n\n\t\tthis.r = r;\n\t\tthis.g = g;\n\t\tthis.b = b;\n\n\t\treturn this;\n\n\t},\n\n\tsetHSL: function () {\n\n\t\tfunction hue2rgb( p, q, t ) {\n\n\t\t\tif ( t < 0 ) t += 1;\n\t\t\tif ( t > 1 ) t -= 1;\n\t\t\tif ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;\n\t\t\tif ( t < 1 / 2 ) return q;\n\t\t\tif ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );\n\t\t\treturn p;\n\n\t\t}\n\n\t\treturn function setHSL( h, s, l ) {\n\n\t\t\t// h,s,l ranges are in 0.0 - 1.0\n\t\t\th = _Math.euclideanModulo( h, 1 );\n\t\t\ts = _Math.clamp( s, 0, 1 );\n\t\t\tl = _Math.clamp( l, 0, 1 );\n\n\t\t\tif ( s === 0 ) {\n\n\t\t\t\tthis.r = this.g = this.b = l;\n\n\t\t\t} else {\n\n\t\t\t\tvar p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );\n\t\t\t\tvar q = ( 2 * l ) - p;\n\n\t\t\t\tthis.r = hue2rgb( q, p, h + 1 / 3 );\n\t\t\t\tthis.g = hue2rgb( q, p, h );\n\t\t\t\tthis.b = hue2rgb( q, p, h - 1 / 3 );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\tsetStyle: function ( style ) {\n\n\t\tfunction handleAlpha( string ) {\n\n\t\t\tif ( string === undefined ) return;\n\n\t\t\tif ( parseFloat( string ) < 1 ) {\n\n\t\t\t\tconsole.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );\n\n\t\t\t}\n\n\t\t}\n\n\n\t\tvar m;\n\n\t\tif ( m = /^((?:rgb|hsl)a?)\\(\\s*([^\\)]*)\\)/.exec( style ) ) {\n\n\t\t\t// rgb / hsl\n\n\t\t\tvar color;\n\t\t\tvar name = m[ 1 ];\n\t\t\tvar components = m[ 2 ];\n\n\t\t\tswitch ( name ) {\n\n\t\t\t\tcase 'rgb':\n\t\t\t\tcase 'rgba':\n\n\t\t\t\t\tif ( color = /^(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*(,\\s*([0-9]*\\.?[0-9]+)\\s*)?$/.exec( components ) ) {\n\n\t\t\t\t\t\t// rgb(255,0,0) rgba(255,0,0,0.5)\n\t\t\t\t\t\tthis.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;\n\t\t\t\t\t\tthis.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;\n\t\t\t\t\t\tthis.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;\n\n\t\t\t\t\t\thandleAlpha( color[ 5 ] );\n\n\t\t\t\t\t\treturn this;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( color = /^(\\d+)\\%\\s*,\\s*(\\d+)\\%\\s*,\\s*(\\d+)\\%\\s*(,\\s*([0-9]*\\.?[0-9]+)\\s*)?$/.exec( components ) ) {\n\n\t\t\t\t\t\t// rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)\n\t\t\t\t\t\tthis.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;\n\t\t\t\t\t\tthis.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;\n\t\t\t\t\t\tthis.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;\n\n\t\t\t\t\t\thandleAlpha( color[ 5 ] );\n\n\t\t\t\t\t\treturn this;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'hsl':\n\t\t\t\tcase 'hsla':\n\n\t\t\t\t\tif ( color = /^([0-9]*\\.?[0-9]+)\\s*,\\s*(\\d+)\\%\\s*,\\s*(\\d+)\\%\\s*(,\\s*([0-9]*\\.?[0-9]+)\\s*)?$/.exec( components ) ) {\n\n\t\t\t\t\t\t// hsl(120,50%,50%) hsla(120,50%,50%,0.5)\n\t\t\t\t\t\tvar h = parseFloat( color[ 1 ] ) / 360;\n\t\t\t\t\t\tvar s = parseInt( color[ 2 ], 10 ) / 100;\n\t\t\t\t\t\tvar l = parseInt( color[ 3 ], 10 ) / 100;\n\n\t\t\t\t\t\thandleAlpha( color[ 5 ] );\n\n\t\t\t\t\t\treturn this.setHSL( h, s, l );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t} else if ( m = /^\\#([A-Fa-f0-9]+)$/.exec( style ) ) {\n\n\t\t\t// hex color\n\n\t\t\tvar hex = m[ 1 ];\n\t\t\tvar size = hex.length;\n\n\t\t\tif ( size === 3 ) {\n\n\t\t\t\t// #ff0\n\t\t\t\tthis.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255;\n\t\t\t\tthis.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;\n\t\t\t\tthis.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;\n\n\t\t\t\treturn this;\n\n\t\t\t} else if ( size === 6 ) {\n\n\t\t\t\t// #ff0000\n\t\t\t\tthis.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255;\n\t\t\t\tthis.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;\n\t\t\t\tthis.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;\n\n\t\t\t\treturn this;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( style && style.length > 0 ) {\n\n\t\t\t// color keywords\n\t\t\tvar hex = ColorKeywords[ style ];\n\n\t\t\tif ( hex !== undefined ) {\n\n\t\t\t\t// red\n\t\t\t\tthis.setHex( hex );\n\n\t\t\t} else {\n\n\t\t\t\t// unknown color\n\t\t\t\tconsole.warn( 'THREE.Color: Unknown color ' + style );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor( this.r, this.g, this.b );\n\n\t},\n\n\tcopy: function ( color ) {\n\n\t\tthis.r = color.r;\n\t\tthis.g = color.g;\n\t\tthis.b = color.b;\n\n\t\treturn this;\n\n\t},\n\n\tcopyGammaToLinear: function ( color, gammaFactor ) {\n\n\t\tif ( gammaFactor === undefined ) gammaFactor = 2.0;\n\n\t\tthis.r = Math.pow( color.r, gammaFactor );\n\t\tthis.g = Math.pow( color.g, gammaFactor );\n\t\tthis.b = Math.pow( color.b, gammaFactor );\n\n\t\treturn this;\n\n\t},\n\n\tcopyLinearToGamma: function ( color, gammaFactor ) {\n\n\t\tif ( gammaFactor === undefined ) gammaFactor = 2.0;\n\n\t\tvar safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0;\n\n\t\tthis.r = Math.pow( color.r, safeInverse );\n\t\tthis.g = Math.pow( color.g, safeInverse );\n\t\tthis.b = Math.pow( color.b, safeInverse );\n\n\t\treturn this;\n\n\t},\n\n\tconvertGammaToLinear: function () {\n\n\t\tvar r = this.r, g = this.g, b = this.b;\n\n\t\tthis.r = r * r;\n\t\tthis.g = g * g;\n\t\tthis.b = b * b;\n\n\t\treturn this;\n\n\t},\n\n\tconvertLinearToGamma: function () {\n\n\t\tthis.r = Math.sqrt( this.r );\n\t\tthis.g = Math.sqrt( this.g );\n\t\tthis.b = Math.sqrt( this.b );\n\n\t\treturn this;\n\n\t},\n\n\tgetHex: function () {\n\n\t\treturn ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;\n\n\t},\n\n\tgetHexString: function () {\n\n\t\treturn ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );\n\n\t},\n\n\tgetHSL: function ( optionalTarget ) {\n\n\t\t// h,s,l ranges are in 0.0 - 1.0\n\n\t\tvar hsl = optionalTarget || { h: 0, s: 0, l: 0 };\n\n\t\tvar r = this.r, g = this.g, b = this.b;\n\n\t\tvar max = Math.max( r, g, b );\n\t\tvar min = Math.min( r, g, b );\n\n\t\tvar hue, saturation;\n\t\tvar lightness = ( min + max ) / 2.0;\n\n\t\tif ( min === max ) {\n\n\t\t\thue = 0;\n\t\t\tsaturation = 0;\n\n\t\t} else {\n\n\t\t\tvar delta = max - min;\n\n\t\t\tsaturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );\n\n\t\t\tswitch ( max ) {\n\n\t\t\t\tcase r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;\n\t\t\t\tcase g: hue = ( b - r ) / delta + 2; break;\n\t\t\t\tcase b: hue = ( r - g ) / delta + 4; break;\n\n\t\t\t}\n\n\t\t\thue /= 6;\n\n\t\t}\n\n\t\thsl.h = hue;\n\t\thsl.s = saturation;\n\t\thsl.l = lightness;\n\n\t\treturn hsl;\n\n\t},\n\n\tgetStyle: function () {\n\n\t\treturn 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';\n\n\t},\n\n\toffsetHSL: function ( h, s, l ) {\n\n\t\tvar hsl = this.getHSL();\n\n\t\thsl.h += h; hsl.s += s; hsl.l += l;\n\n\t\tthis.setHSL( hsl.h, hsl.s, hsl.l );\n\n\t\treturn this;\n\n\t},\n\n\tadd: function ( color ) {\n\n\t\tthis.r += color.r;\n\t\tthis.g += color.g;\n\t\tthis.b += color.b;\n\n\t\treturn this;\n\n\t},\n\n\taddColors: function ( color1, color2 ) {\n\n\t\tthis.r = color1.r + color2.r;\n\t\tthis.g = color1.g + color2.g;\n\t\tthis.b = color1.b + color2.b;\n\n\t\treturn this;\n\n\t},\n\n\taddScalar: function ( s ) {\n\n\t\tthis.r += s;\n\t\tthis.g += s;\n\t\tthis.b += s;\n\n\t\treturn this;\n\n\t},\n\n\tsub: function( color ) {\n\n\t\tthis.r = Math.max( 0, this.r - color.r );\n\t\tthis.g = Math.max( 0, this.g - color.g );\n\t\tthis.b = Math.max( 0, this.b - color.b );\n\n\t\treturn this;\n\n\t},\n\n\tmultiply: function ( color ) {\n\n\t\tthis.r *= color.r;\n\t\tthis.g *= color.g;\n\t\tthis.b *= color.b;\n\n\t\treturn this;\n\n\t},\n\n\tmultiplyScalar: function ( s ) {\n\n\t\tthis.r *= s;\n\t\tthis.g *= s;\n\t\tthis.b *= s;\n\n\t\treturn this;\n\n\t},\n\n\tlerp: function ( color, alpha ) {\n\n\t\tthis.r += ( color.r - this.r ) * alpha;\n\t\tthis.g += ( color.g - this.g ) * alpha;\n\t\tthis.b += ( color.b - this.b ) * alpha;\n\n\t\treturn this;\n\n\t},\n\n\tequals: function ( c ) {\n\n\t\treturn ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );\n\n\t},\n\n\tfromArray: function ( array, offset ) {\n\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tthis.r = array[ offset ];\n\t\tthis.g = array[ offset + 1 ];\n\t\tthis.b = array[ offset + 2 ];\n\n\t\treturn this;\n\n\t},\n\n\ttoArray: function ( array, offset ) {\n\n\t\tif ( array === undefined ) array = [];\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tarray[ offset ] = this.r;\n\t\tarray[ offset + 1 ] = this.g;\n\t\tarray[ offset + 2 ] = this.b;\n\n\t\treturn array;\n\n\t},\n\n\ttoJSON: function () {\n\n\t\treturn this.getHex();\n\n\t}\n\n};\n\nvar ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,\n'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,\n'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,\n'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,\n'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,\n'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,\n'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,\n'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,\n'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,\n'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,\n'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,\n'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,\n'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,\n'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,\n'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,\n'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,\n'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,\n'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,\n'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,\n'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,\n'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,\n'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,\n'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,\n'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };\n\n/**\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {\n\n\tTexture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );\n\n\tthis.image = { data: data, width: width, height: height };\n\n\tthis.magFilter = magFilter !== undefined ? magFilter : NearestFilter;\n\tthis.minFilter = minFilter !== undefined ? minFilter : NearestFilter;\n\n\tthis.generateMipmaps = false;\n\tthis.flipY = false;\n\tthis.unpackAlignment = 1;\n\n}\n\nDataTexture.prototype = Object.create( Texture.prototype );\nDataTexture.prototype.constructor = DataTexture;\n\nDataTexture.prototype.isDataTexture = true;\n\n/**\n * Uniforms library for shared webgl shaders\n */\n\nvar UniformsLib = {\n\n\tcommon: {\n\n\t\tdiffuse: { value: new Color( 0xeeeeee ) },\n\t\topacity: { value: 1.0 },\n\n\t\tmap: { value: null },\n\t\toffsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) },\n\n\t\tspecularMap: { value: null },\n\t\talphaMap: { value: null },\n\n\t\tenvMap: { value: null },\n\t\tflipEnvMap: { value: - 1 },\n\t\treflectivity: { value: 1.0 },\n\t\trefractionRatio: { value: 0.98 }\n\n\t},\n\n\taomap: {\n\n\t\taoMap: { value: null },\n\t\taoMapIntensity: { value: 1 }\n\n\t},\n\n\tlightmap: {\n\n\t\tlightMap: { value: null },\n\t\tlightMapIntensity: { value: 1 }\n\n\t},\n\n\temissivemap: {\n\n\t\temissiveMap: { value: null }\n\n\t},\n\n\tbumpmap: {\n\n\t\tbumpMap: { value: null },\n\t\tbumpScale: { value: 1 }\n\n\t},\n\n\tnormalmap: {\n\n\t\tnormalMap: { value: null },\n\t\tnormalScale: { value: new Vector2( 1, 1 ) }\n\n\t},\n\n\tdisplacementmap: {\n\n\t\tdisplacementMap: { value: null },\n\t\tdisplacementScale: { value: 1 },\n\t\tdisplacementBias: { value: 0 }\n\n\t},\n\n\troughnessmap: {\n\n\t\troughnessMap: { value: null }\n\n\t},\n\n\tmetalnessmap: {\n\n\t\tmetalnessMap: { value: null }\n\n\t},\n\n\tgradientmap: {\n\n\t\tgradientMap: { value: null }\n\n\t},\n\n\tfog: {\n\n\t\tfogDensity: { value: 0.00025 },\n\t\tfogNear: { value: 1 },\n\t\tfogFar: { value: 2000 },\n\t\tfogColor: { value: new Color( 0xffffff ) }\n\n\t},\n\n\tlights: {\n\n\t\tambientLightColor: { value: [] },\n\n\t\tdirectionalLights: { value: [], properties: {\n\t\t\tdirection: {},\n\t\t\tcolor: {},\n\n\t\t\tshadow: {},\n\t\t\tshadowBias: {},\n\t\t\tshadowRadius: {},\n\t\t\tshadowMapSize: {}\n\t\t} },\n\n\t\tdirectionalShadowMap: { value: [] },\n\t\tdirectionalShadowMatrix: { value: [] },\n\n\t\tspotLights: { value: [], properties: {\n\t\t\tcolor: {},\n\t\t\tposition: {},\n\t\t\tdirection: {},\n\t\t\tdistance: {},\n\t\t\tconeCos: {},\n\t\t\tpenumbraCos: {},\n\t\t\tdecay: {},\n\n\t\t\tshadow: {},\n\t\t\tshadowBias: {},\n\t\t\tshadowRadius: {},\n\t\t\tshadowMapSize: {}\n\t\t} },\n\n\t\tspotShadowMap: { value: [] },\n\t\tspotShadowMatrix: { value: [] },\n\n\t\tpointLights: { value: [], properties: {\n\t\t\tcolor: {},\n\t\t\tposition: {},\n\t\t\tdecay: {},\n\t\t\tdistance: {},\n\n\t\t\tshadow: {},\n\t\t\tshadowBias: {},\n\t\t\tshadowRadius: {},\n\t\t\tshadowMapSize: {}\n\t\t} },\n\n\t\tpointShadowMap: { value: [] },\n\t\tpointShadowMatrix: { value: [] },\n\n\t\themisphereLights: { value: [], properties: {\n\t\t\tdirection: {},\n\t\t\tskyColor: {},\n\t\t\tgroundColor: {}\n\t\t} },\n\n\t\t// TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src\n\t\trectAreaLights: { value: [], properties: {\n\t\t\tcolor: {},\n\t\t\tposition: {},\n\t\t\twidth: {},\n\t\t\theight: {}\n\t\t} }\n\n\t},\n\n\tpoints: {\n\n\t\tdiffuse: { value: new Color( 0xeeeeee ) },\n\t\topacity: { value: 1.0 },\n\t\tsize: { value: 1.0 },\n\t\tscale: { value: 1.0 },\n\t\tmap: { value: null },\n\t\toffsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) }\n\n\t}\n\n};\n\n/**\n * @author alteredq / http://alteredqualia.com/\n * @author mrdoob / http://mrdoob.com/\n * @author mikael emtinger / http://gomo.se/\n */\n\nvar ShaderLib = {\n\n\tbasic: {\n\n\t\tuniforms: UniformsUtils.merge( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.aomap,\n\t\t\tUniformsLib.lightmap,\n\t\t\tUniformsLib.fog\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshbasic_vert,\n\t\tfragmentShader: ShaderChunk.meshbasic_frag\n\n\t},\n\n\tlambert: {\n\n\t\tuniforms: UniformsUtils.merge( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.aomap,\n\t\t\tUniformsLib.lightmap,\n\t\t\tUniformsLib.emissivemap,\n\t\t\tUniformsLib.fog,\n\t\t\tUniformsLib.lights,\n\t\t\t{\n\t\t\t\temissive: { value: new Color( 0x000000 ) }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshlambert_vert,\n\t\tfragmentShader: ShaderChunk.meshlambert_frag\n\n\t},\n\n\tphong: {\n\n\t\tuniforms: UniformsUtils.merge( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.aomap,\n\t\t\tUniformsLib.lightmap,\n\t\t\tUniformsLib.emissivemap,\n\t\t\tUniformsLib.bumpmap,\n\t\t\tUniformsLib.normalmap,\n\t\t\tUniformsLib.displacementmap,\n\t\t\tUniformsLib.gradientmap,\n\t\t\tUniformsLib.fog,\n\t\t\tUniformsLib.lights,\n\t\t\t{\n\t\t\t\temissive: { value: new Color( 0x000000 ) },\n\t\t\t\tspecular: { value: new Color( 0x111111 ) },\n\t\t\t\tshininess: { value: 30 }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshphong_vert,\n\t\tfragmentShader: ShaderChunk.meshphong_frag\n\n\t},\n\n\tstandard: {\n\n\t\tuniforms: UniformsUtils.merge( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.aomap,\n\t\t\tUniformsLib.lightmap,\n\t\t\tUniformsLib.emissivemap,\n\t\t\tUniformsLib.bumpmap,\n\t\t\tUniformsLib.normalmap,\n\t\t\tUniformsLib.displacementmap,\n\t\t\tUniformsLib.roughnessmap,\n\t\t\tUniformsLib.metalnessmap,\n\t\t\tUniformsLib.fog,\n\t\t\tUniformsLib.lights,\n\t\t\t{\n\t\t\t\temissive: { value: new Color( 0x000000 ) },\n\t\t\t\troughness: { value: 0.5 },\n\t\t\t\tmetalness: { value: 0 },\n\t\t\t\tenvMapIntensity: { value: 1 } // temporary\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshphysical_vert,\n\t\tfragmentShader: ShaderChunk.meshphysical_frag\n\n\t},\n\n\tpoints: {\n\n\t\tuniforms: UniformsUtils.merge( [\n\t\t\tUniformsLib.points,\n\t\t\tUniformsLib.fog\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.points_vert,\n\t\tfragmentShader: ShaderChunk.points_frag\n\n\t},\n\n\tdashed: {\n\n\t\tuniforms: UniformsUtils.merge( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.fog,\n\t\t\t{\n\t\t\t\tscale: { value: 1 },\n\t\t\t\tdashSize: { value: 1 },\n\t\t\t\ttotalSize: { value: 2 }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.linedashed_vert,\n\t\tfragmentShader: ShaderChunk.linedashed_frag\n\n\t},\n\n\tdepth: {\n\n\t\tuniforms: UniformsUtils.merge( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.displacementmap\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.depth_vert,\n\t\tfragmentShader: ShaderChunk.depth_frag\n\n\t},\n\n\tnormal: {\n\n\t\tuniforms: UniformsUtils.merge( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.bumpmap,\n\t\t\tUniformsLib.normalmap,\n\t\t\tUniformsLib.displacementmap,\n\t\t\t{\n\t\t\t\topacity: { value: 1.0 }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.normal_vert,\n\t\tfragmentShader: ShaderChunk.normal_frag\n\n\t},\n\n\t/* -------------------------------------------------------------------------\n\t//\tCube map shader\n\t ------------------------------------------------------------------------- */\n\n\tcube: {\n\n\t\tuniforms: {\n\t\t\ttCube: { value: null },\n\t\t\ttFlip: { value: - 1 },\n\t\t\topacity: { value: 1.0 }\n\t\t},\n\n\t\tvertexShader: ShaderChunk.cube_vert,\n\t\tfragmentShader: ShaderChunk.cube_frag\n\n\t},\n\n\t/* -------------------------------------------------------------------------\n\t//\tCube map shader\n\t ------------------------------------------------------------------------- */\n\n\tequirect: {\n\n\t\tuniforms: {\n\t\t\ttEquirect: { value: null },\n\t\t\ttFlip: { value: - 1 }\n\t\t},\n\n\t\tvertexShader: ShaderChunk.equirect_vert,\n\t\tfragmentShader: ShaderChunk.equirect_frag\n\n\t},\n\n\tdistanceRGBA: {\n\n\t\tuniforms: {\n\t\t\tlightPos: { value: new Vector3() }\n\t\t},\n\n\t\tvertexShader: ShaderChunk.distanceRGBA_vert,\n\t\tfragmentShader: ShaderChunk.distanceRGBA_frag\n\n\t}\n\n};\n\nShaderLib.physical = {\n\n\tuniforms: UniformsUtils.merge( [\n\t\tShaderLib.standard.uniforms,\n\t\t{\n\t\t\tclearCoat: { value: 0 },\n\t\t\tclearCoatRoughness: { value: 0 }\n\t\t}\n\t] ),\n\n\tvertexShader: ShaderChunk.meshphysical_vert,\n\tfragmentShader: ShaderChunk.meshphysical_frag\n\n};\n\n/**\n * @author bhouston / http://clara.io\n */\n\nfunction Box2( min, max ) {\n\n\tthis.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity );\n\tthis.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity );\n\n}\n\nBox2.prototype = {\n\n\tconstructor: Box2,\n\n\tset: function ( min, max ) {\n\n\t\tthis.min.copy( min );\n\t\tthis.max.copy( max );\n\n\t\treturn this;\n\n\t},\n\n\tsetFromPoints: function ( points ) {\n\n\t\tthis.makeEmpty();\n\n\t\tfor ( var i = 0, il = points.length; i < il; i ++ ) {\n\n\t\t\tthis.expandByPoint( points[ i ] );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tsetFromCenterAndSize: function () {\n\n\t\tvar v1 = new Vector2();\n\n\t\treturn function setFromCenterAndSize( center, size ) {\n\n\t\t\tvar halfSize = v1.copy( size ).multiplyScalar( 0.5 );\n\t\t\tthis.min.copy( center ).sub( halfSize );\n\t\t\tthis.max.copy( center ).add( halfSize );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\tclone: function () {\n\n\t\treturn new this.constructor().copy( this );\n\n\t},\n\n\tcopy: function ( box ) {\n\n\t\tthis.min.copy( box.min );\n\t\tthis.max.copy( box.max );\n\n\t\treturn this;\n\n\t},\n\n\tmakeEmpty: function () {\n\n\t\tthis.min.x = this.min.y = + Infinity;\n\t\tthis.max.x = this.max.y = - Infinity;\n\n\t\treturn this;\n\n\t},\n\n\tisEmpty: function () {\n\n\t\t// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes\n\n\t\treturn ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );\n\n\t},\n\n\tgetCenter: function ( optionalTarget ) {\n\n\t\tvar result = optionalTarget || new Vector2();\n\t\treturn this.isEmpty() ? result.set( 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );\n\n\t},\n\n\tgetSize: function ( optionalTarget ) {\n\n\t\tvar result = optionalTarget || new Vector2();\n\t\treturn this.isEmpty() ? result.set( 0, 0 ) : result.subVectors( this.max, this.min );\n\n\t},\n\n\texpandByPoint: function ( point ) {\n\n\t\tthis.min.min( point );\n\t\tthis.max.max( point );\n\n\t\treturn this;\n\n\t},\n\n\texpandByVector: function ( vector ) {\n\n\t\tthis.min.sub( vector );\n\t\tthis.max.add( vector );\n\n\t\treturn this;\n\n\t},\n\n\texpandByScalar: function ( scalar ) {\n\n\t\tthis.min.addScalar( - scalar );\n\t\tthis.max.addScalar( scalar );\n\n\t\treturn this;\n\n\t},\n\n\tcontainsPoint: function ( point ) {\n\n\t\treturn point.x < this.min.x || point.x > this.max.x ||\n\t\t\tpoint.y < this.min.y || point.y > this.max.y ? false : true;\n\n\t},\n\n\tcontainsBox: function ( box ) {\n\n\t\treturn this.min.x <= box.min.x && box.max.x <= this.max.x &&\n\t\t\tthis.min.y <= box.min.y && box.max.y <= this.max.y;\n\n\t},\n\n\tgetParameter: function ( point, optionalTarget ) {\n\n\t\t// This can potentially have a divide by zero if the box\n\t\t// has a size dimension of 0.\n\n\t\tvar result = optionalTarget || new Vector2();\n\n\t\treturn result.set(\n\t\t\t( point.x - this.min.x ) / ( this.max.x - this.min.x ),\n\t\t\t( point.y - this.min.y ) / ( this.max.y - this.min.y )\n\t\t);\n\n\t},\n\n\tintersectsBox: function ( box ) {\n\n\t\t// using 6 splitting planes to rule out intersections.\n\t\treturn box.max.x < this.min.x || box.min.x > this.max.x ||\n\t\t\tbox.max.y < this.min.y || box.min.y > this.max.y ? false : true;\n\n\t},\n\n\tclampPoint: function ( point, optionalTarget ) {\n\n\t\tvar result = optionalTarget || new Vector2();\n\t\treturn result.copy( point ).clamp( this.min, this.max );\n\n\t},\n\n\tdistanceToPoint: function () {\n\n\t\tvar v1 = new Vector2();\n\n\t\treturn function distanceToPoint( point ) {\n\n\t\t\tvar clampedPoint = v1.copy( point ).clamp( this.min, this.max );\n\t\t\treturn clampedPoint.sub( point ).length();\n\n\t\t};\n\n\t}(),\n\n\tintersect: function ( box ) {\n\n\t\tthis.min.max( box.min );\n\t\tthis.max.min( box.max );\n\n\t\treturn this;\n\n\t},\n\n\tunion: function ( box ) {\n\n\t\tthis.min.min( box.min );\n\t\tthis.max.max( box.max );\n\n\t\treturn this;\n\n\t},\n\n\ttranslate: function ( offset ) {\n\n\t\tthis.min.add( offset );\n\t\tthis.max.add( offset );\n\n\t\treturn this;\n\n\t},\n\n\tequals: function ( box ) {\n\n\t\treturn box.min.equals( this.min ) && box.max.equals( this.max );\n\n\t}\n\n};\n\n/**\n * @author mikael emtinger / http://gomo.se/\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction LensFlarePlugin( renderer, flares ) {\n\n\tvar gl = renderer.context;\n\tvar state = renderer.state;\n\n\tvar vertexBuffer, elementBuffer;\n\tvar shader, program, attributes, uniforms;\n\n\tvar tempTexture, occlusionTexture;\n\n\tfunction init() {\n\n\t\tvar vertices = new Float32Array( [\n\t\t\t- 1, - 1, 0, 0,\n\t\t\t 1, - 1, 1, 0,\n\t\t\t 1, 1, 1, 1,\n\t\t\t- 1, 1, 0, 1\n\t\t] );\n\n\t\tvar faces = new Uint16Array( [\n\t\t\t0, 1, 2,\n\t\t\t0, 2, 3\n\t\t] );\n\n\t\t// buffers\n\n\t\tvertexBuffer = gl.createBuffer();\n\t\telementBuffer = gl.createBuffer();\n\n\t\tgl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );\n\t\tgl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );\n\n\t\tgl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );\n\t\tgl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );\n\n\t\t// textures\n\n\t\ttempTexture = gl.createTexture();\n\t\tocclusionTexture = gl.createTexture();\n\n\t\tstate.bindTexture( gl.TEXTURE_2D, tempTexture );\n\t\tgl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, 16, 16, 0, gl.RGB, gl.UNSIGNED_BYTE, null );\n\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );\n\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );\n\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );\n\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );\n\n\t\tstate.bindTexture( gl.TEXTURE_2D, occlusionTexture );\n\t\tgl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null );\n\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );\n\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );\n\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );\n\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );\n\n\t\tshader = {\n\n\t\t\tvertexShader: [\n\n\t\t\t\t\"uniform lowp int renderType;\",\n\n\t\t\t\t\"uniform vec3 screenPosition;\",\n\t\t\t\t\"uniform vec2 scale;\",\n\t\t\t\t\"uniform float rotation;\",\n\n\t\t\t\t\"uniform sampler2D occlusionMap;\",\n\n\t\t\t\t\"attribute vec2 position;\",\n\t\t\t\t\"attribute vec2 uv;\",\n\n\t\t\t\t\"varying vec2 vUV;\",\n\t\t\t\t\"varying float vVisibility;\",\n\n\t\t\t\t\"void main() {\",\n\n\t\t\t\t\t\"vUV = uv;\",\n\n\t\t\t\t\t\"vec2 pos = position;\",\n\n\t\t\t\t\t\"if ( renderType == 2 ) {\",\n\n\t\t\t\t\t\t\"vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );\",\n\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );\",\n\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );\",\n\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );\",\n\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );\",\n\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );\",\n\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );\",\n\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );\",\n\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );\",\n\n\t\t\t\t\t\t\"vVisibility = visibility.r / 9.0;\",\n\t\t\t\t\t\t\"vVisibility *= 1.0 - visibility.g / 9.0;\",\n\t\t\t\t\t\t\"vVisibility *= visibility.b / 9.0;\",\n\t\t\t\t\t\t\"vVisibility *= 1.0 - visibility.a / 9.0;\",\n\n\t\t\t\t\t\t\"pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;\",\n\t\t\t\t\t\t\"pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;\",\n\n\t\t\t\t\t\"}\",\n\n\t\t\t\t\t\"gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );\",\n\n\t\t\t\t\"}\"\n\n\t\t\t].join( \"\\n\" ),\n\n\t\t\tfragmentShader: [\n\n\t\t\t\t\"uniform lowp int renderType;\",\n\n\t\t\t\t\"uniform sampler2D map;\",\n\t\t\t\t\"uniform float opacity;\",\n\t\t\t\t\"uniform vec3 color;\",\n\n\t\t\t\t\"varying vec2 vUV;\",\n\t\t\t\t\"varying float vVisibility;\",\n\n\t\t\t\t\"void main() {\",\n\n\t\t\t\t\t// pink square\n\n\t\t\t\t\t\"if ( renderType == 0 ) {\",\n\n\t\t\t\t\t\t\"gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );\",\n\n\t\t\t\t\t// restore\n\n\t\t\t\t\t\"} else if ( renderType == 1 ) {\",\n\n\t\t\t\t\t\t\"gl_FragColor = texture2D( map, vUV );\",\n\n\t\t\t\t\t// flare\n\n\t\t\t\t\t\"} else {\",\n\n\t\t\t\t\t\t\"vec4 texture = texture2D( map, vUV );\",\n\t\t\t\t\t\t\"texture.a *= opacity * vVisibility;\",\n\t\t\t\t\t\t\"gl_FragColor = texture;\",\n\t\t\t\t\t\t\"gl_FragColor.rgb *= color;\",\n\n\t\t\t\t\t\"}\",\n\n\t\t\t\t\"}\"\n\n\t\t\t].join( \"\\n\" )\n\n\t\t};\n\n\t\tprogram = createProgram( shader );\n\n\t\tattributes = {\n\t\t\tvertex: gl.getAttribLocation ( program, \"position\" ),\n\t\t\tuv: gl.getAttribLocation ( program, \"uv\" )\n\t\t};\n\n\t\tuniforms = {\n\t\t\trenderType: gl.getUniformLocation( program, \"renderType\" ),\n\t\t\tmap: gl.getUniformLocation( program, \"map\" ),\n\t\t\tocclusionMap: gl.getUniformLocation( program, \"occlusionMap\" ),\n\t\t\topacity: gl.getUniformLocation( program, \"opacity\" ),\n\t\t\tcolor: gl.getUniformLocation( program, \"color\" ),\n\t\t\tscale: gl.getUniformLocation( program, \"scale\" ),\n\t\t\trotation: gl.getUniformLocation( program, \"rotation\" ),\n\t\t\tscreenPosition: gl.getUniformLocation( program, \"screenPosition\" )\n\t\t};\n\n\t}\n\n\t/*\n\t * Render lens flares\n\t * Method: renders 16x16 0xff00ff-colored points scattered over the light source area,\n\t * reads these back and calculates occlusion.\n\t */\n\n\tthis.render = function ( scene, camera, viewport ) {\n\n\t\tif ( flares.length === 0 ) return;\n\n\t\tvar tempPosition = new Vector3();\n\n\t\tvar invAspect = viewport.w / viewport.z,\n\t\t\thalfViewportWidth = viewport.z * 0.5,\n\t\t\thalfViewportHeight = viewport.w * 0.5;\n\n\t\tvar size = 16 / viewport.w,\n\t\t\tscale = new Vector2( size * invAspect, size );\n\n\t\tvar screenPosition = new Vector3( 1, 1, 0 ),\n\t\t\tscreenPositionPixels = new Vector2( 1, 1 );\n\n\t\tvar validArea = new Box2();\n\n\t\tvalidArea.min.set( viewport.x, viewport.y );\n\t\tvalidArea.max.set( viewport.x + ( viewport.z - 16 ), viewport.y + ( viewport.w - 16 ) );\n\n\t\tif ( program === undefined ) {\n\n\t\t\tinit();\n\n\t\t}\n\n\t\tgl.useProgram( program );\n\n\t\tstate.initAttributes();\n\t\tstate.enableAttribute( attributes.vertex );\n\t\tstate.enableAttribute( attributes.uv );\n\t\tstate.disableUnusedAttributes();\n\n\t\t// loop through all lens flares to update their occlusion and positions\n\t\t// setup gl and common used attribs/uniforms\n\n\t\tgl.uniform1i( uniforms.occlusionMap, 0 );\n\t\tgl.uniform1i( uniforms.map, 1 );\n\n\t\tgl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );\n\t\tgl.vertexAttribPointer( attributes.vertex, 2, gl.FLOAT, false, 2 * 8, 0 );\n\t\tgl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 );\n\n\t\tgl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );\n\n\t\tstate.disable( gl.CULL_FACE );\n\t\tstate.setDepthWrite( false );\n\n\t\tfor ( var i = 0, l = flares.length; i < l; i ++ ) {\n\n\t\t\tsize = 16 / viewport.w;\n\t\t\tscale.set( size * invAspect, size );\n\n\t\t\t// calc object screen position\n\n\t\t\tvar flare = flares[ i ];\n\n\t\t\ttempPosition.set( flare.matrixWorld.elements[ 12 ], flare.matrixWorld.elements[ 13 ], flare.matrixWorld.elements[ 14 ] );\n\n\t\t\ttempPosition.applyMatrix4( camera.matrixWorldInverse );\n\t\t\ttempPosition.applyMatrix4( camera.projectionMatrix );\n\n\t\t\t// setup arrays for gl programs\n\n\t\t\tscreenPosition.copy( tempPosition );\n\n\t\t\t// horizontal and vertical coordinate of the lower left corner of the pixels to copy\n\n\t\t\tscreenPositionPixels.x = viewport.x + ( screenPosition.x * halfViewportWidth ) + halfViewportWidth - 8;\n\t\t\tscreenPositionPixels.y = viewport.y + ( screenPosition.y * halfViewportHeight ) + halfViewportHeight - 8;\n\n\t\t\t// screen cull\n\n\t\t\tif ( validArea.containsPoint( screenPositionPixels ) === true ) {\n\n\t\t\t\t// save current RGB to temp texture\n\n\t\t\t\tstate.activeTexture( gl.TEXTURE0 );\n\t\t\t\tstate.bindTexture( gl.TEXTURE_2D, null );\n\t\t\t\tstate.activeTexture( gl.TEXTURE1 );\n\t\t\t\tstate.bindTexture( gl.TEXTURE_2D, tempTexture );\n\t\t\t\tgl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 );\n\n\n\t\t\t\t// render pink quad\n\n\t\t\t\tgl.uniform1i( uniforms.renderType, 0 );\n\t\t\t\tgl.uniform2f( uniforms.scale, scale.x, scale.y );\n\t\t\t\tgl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );\n\n\t\t\t\tstate.disable( gl.BLEND );\n\t\t\t\tstate.enable( gl.DEPTH_TEST );\n\n\t\t\t\tgl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );\n\n\n\t\t\t\t// copy result to occlusionMap\n\n\t\t\t\tstate.activeTexture( gl.TEXTURE0 );\n\t\t\t\tstate.bindTexture( gl.TEXTURE_2D, occlusionTexture );\n\t\t\t\tgl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 );\n\n\n\t\t\t\t// restore graphics\n\n\t\t\t\tgl.uniform1i( uniforms.renderType, 1 );\n\t\t\t\tstate.disable( gl.DEPTH_TEST );\n\n\t\t\t\tstate.activeTexture( gl.TEXTURE1 );\n\t\t\t\tstate.bindTexture( gl.TEXTURE_2D, tempTexture );\n\t\t\t\tgl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );\n\n\n\t\t\t\t// update object positions\n\n\t\t\t\tflare.positionScreen.copy( screenPosition );\n\n\t\t\t\tif ( flare.customUpdateCallback ) {\n\n\t\t\t\t\tflare.customUpdateCallback( flare );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tflare.updateLensFlares();\n\n\t\t\t\t}\n\n\t\t\t\t// render flares\n\n\t\t\t\tgl.uniform1i( uniforms.renderType, 2 );\n\t\t\t\tstate.enable( gl.BLEND );\n\n\t\t\t\tfor ( var j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) {\n\n\t\t\t\t\tvar sprite = flare.lensFlares[ j ];\n\n\t\t\t\t\tif ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) {\n\n\t\t\t\t\t\tscreenPosition.x = sprite.x;\n\t\t\t\t\t\tscreenPosition.y = sprite.y;\n\t\t\t\t\t\tscreenPosition.z = sprite.z;\n\n\t\t\t\t\t\tsize = sprite.size * sprite.scale / viewport.w;\n\n\t\t\t\t\t\tscale.x = size * invAspect;\n\t\t\t\t\t\tscale.y = size;\n\n\t\t\t\t\t\tgl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );\n\t\t\t\t\t\tgl.uniform2f( uniforms.scale, scale.x, scale.y );\n\t\t\t\t\t\tgl.uniform1f( uniforms.rotation, sprite.rotation );\n\n\t\t\t\t\t\tgl.uniform1f( uniforms.opacity, sprite.opacity );\n\t\t\t\t\t\tgl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b );\n\n\t\t\t\t\t\tstate.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst );\n\t\t\t\t\t\trenderer.setTexture2D( sprite.texture, 1 );\n\n\t\t\t\t\t\tgl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t// restore gl\n\n\t\tstate.enable( gl.CULL_FACE );\n\t\tstate.enable( gl.DEPTH_TEST );\n\t\tstate.setDepthWrite( true );\n\n\t\trenderer.resetGLState();\n\n\t};\n\n\tfunction createProgram( shader ) {\n\n\t\tvar program = gl.createProgram();\n\n\t\tvar fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );\n\t\tvar vertexShader = gl.createShader( gl.VERTEX_SHADER );\n\n\t\tvar prefix = \"precision \" + renderer.getPrecision() + \" float;\\n\";\n\n\t\tgl.shaderSource( fragmentShader, prefix + shader.fragmentShader );\n\t\tgl.shaderSource( vertexShader, prefix + shader.vertexShader );\n\n\t\tgl.compileShader( fragmentShader );\n\t\tgl.compileShader( vertexShader );\n\n\t\tgl.attachShader( program, fragmentShader );\n\t\tgl.attachShader( program, vertexShader );\n\n\t\tgl.linkProgram( program );\n\n\t\treturn program;\n\n\t}\n\n}\n\n/**\n * @author mikael emtinger / http://gomo.se/\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction SpritePlugin( renderer, sprites ) {\n\n\tvar gl = renderer.context;\n\tvar state = renderer.state;\n\n\tvar vertexBuffer, elementBuffer;\n\tvar program, attributes, uniforms;\n\n\tvar texture;\n\n\t// decompose matrixWorld\n\n\tvar spritePosition = new Vector3();\n\tvar spriteRotation = new Quaternion();\n\tvar spriteScale = new Vector3();\n\n\tfunction init() {\n\n\t\tvar vertices = new Float32Array( [\n\t\t\t- 0.5, - 0.5, 0, 0,\n\t\t\t 0.5, - 0.5, 1, 0,\n\t\t\t 0.5, 0.5, 1, 1,\n\t\t\t- 0.5, 0.5, 0, 1\n\t\t] );\n\n\t\tvar faces = new Uint16Array( [\n\t\t\t0, 1, 2,\n\t\t\t0, 2, 3\n\t\t] );\n\n\t\tvertexBuffer = gl.createBuffer();\n\t\telementBuffer = gl.createBuffer();\n\n\t\tgl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );\n\t\tgl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );\n\n\t\tgl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );\n\t\tgl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );\n\n\t\tprogram = createProgram();\n\n\t\tattributes = {\n\t\t\tposition:\t\t\tgl.getAttribLocation ( program, 'position' ),\n\t\t\tuv:\t\t\t\t\tgl.getAttribLocation ( program, 'uv' )\n\t\t};\n\n\t\tuniforms = {\n\t\t\tuvOffset:\t\t\tgl.getUniformLocation( program, 'uvOffset' ),\n\t\t\tuvScale:\t\t\tgl.getUniformLocation( program, 'uvScale' ),\n\n\t\t\trotation:\t\t\tgl.getUniformLocation( program, 'rotation' ),\n\t\t\tscale:\t\t\t\tgl.getUniformLocation( program, 'scale' ),\n\n\t\t\tcolor:\t\t\t\tgl.getUniformLocation( program, 'color' ),\n\t\t\tmap:\t\t\t\tgl.getUniformLocation( program, 'map' ),\n\t\t\topacity:\t\t\tgl.getUniformLocation( program, 'opacity' ),\n\n\t\t\tmodelViewMatrix: \tgl.getUniformLocation( program, 'modelViewMatrix' ),\n\t\t\tprojectionMatrix:\tgl.getUniformLocation( program, 'projectionMatrix' ),\n\n\t\t\tfogType:\t\t\tgl.getUniformLocation( program, 'fogType' ),\n\t\t\tfogDensity:\t\t\tgl.getUniformLocation( program, 'fogDensity' ),\n\t\t\tfogNear:\t\t\tgl.getUniformLocation( program, 'fogNear' ),\n\t\t\tfogFar:\t\t\t\tgl.getUniformLocation( program, 'fogFar' ),\n\t\t\tfogColor:\t\t\tgl.getUniformLocation( program, 'fogColor' ),\n\n\t\t\talphaTest:\t\t\tgl.getUniformLocation( program, 'alphaTest' )\n\t\t};\n\n\t\tvar canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );\n\t\tcanvas.width = 8;\n\t\tcanvas.height = 8;\n\n\t\tvar context = canvas.getContext( '2d' );\n\t\tcontext.fillStyle = 'white';\n\t\tcontext.fillRect( 0, 0, 8, 8 );\n\n\t\ttexture = new Texture( canvas );\n\t\ttexture.needsUpdate = true;\n\n\t}\n\n\tthis.render = function ( scene, camera ) {\n\n\t\tif ( sprites.length === 0 ) return;\n\n\t\t// setup gl\n\n\t\tif ( program === undefined ) {\n\n\t\t\tinit();\n\n\t\t}\n\n\t\tgl.useProgram( program );\n\n\t\tstate.initAttributes();\n\t\tstate.enableAttribute( attributes.position );\n\t\tstate.enableAttribute( attributes.uv );\n\t\tstate.disableUnusedAttributes();\n\n\t\tstate.disable( gl.CULL_FACE );\n\t\tstate.enable( gl.BLEND );\n\n\t\tgl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );\n\t\tgl.vertexAttribPointer( attributes.position, 2, gl.FLOAT, false, 2 * 8, 0 );\n\t\tgl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 );\n\n\t\tgl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );\n\n\t\tgl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements );\n\n\t\tstate.activeTexture( gl.TEXTURE0 );\n\t\tgl.uniform1i( uniforms.map, 0 );\n\n\t\tvar oldFogType = 0;\n\t\tvar sceneFogType = 0;\n\t\tvar fog = scene.fog;\n\n\t\tif ( fog ) {\n\n\t\t\tgl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b );\n\n\t\t\tif ( fog.isFog ) {\n\n\t\t\t\tgl.uniform1f( uniforms.fogNear, fog.near );\n\t\t\t\tgl.uniform1f( uniforms.fogFar, fog.far );\n\n\t\t\t\tgl.uniform1i( uniforms.fogType, 1 );\n\t\t\t\toldFogType = 1;\n\t\t\t\tsceneFogType = 1;\n\n\t\t\t} else if ( fog.isFogExp2 ) {\n\n\t\t\t\tgl.uniform1f( uniforms.fogDensity, fog.density );\n\n\t\t\t\tgl.uniform1i( uniforms.fogType, 2 );\n\t\t\t\toldFogType = 2;\n\t\t\t\tsceneFogType = 2;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tgl.uniform1i( uniforms.fogType, 0 );\n\t\t\toldFogType = 0;\n\t\t\tsceneFogType = 0;\n\n\t\t}\n\n\n\t\t// update positions and sort\n\n\t\tfor ( var i = 0, l = sprites.length; i < l; i ++ ) {\n\n\t\t\tvar sprite = sprites[ i ];\n\n\t\t\tsprite.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld );\n\t\t\tsprite.z = - sprite.modelViewMatrix.elements[ 14 ];\n\n\t\t}\n\n\t\tsprites.sort( painterSortStable );\n\n\t\t// render all sprites\n\n\t\tvar scale = [];\n\n\t\tfor ( var i = 0, l = sprites.length; i < l; i ++ ) {\n\n\t\t\tvar sprite = sprites[ i ];\n\t\t\tvar material = sprite.material;\n\n\t\t\tif ( material.visible === false ) continue;\n\n\t\t\tgl.uniform1f( uniforms.alphaTest, material.alphaTest );\n\t\t\tgl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite.modelViewMatrix.elements );\n\n\t\t\tsprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale );\n\n\t\t\tscale[ 0 ] = spriteScale.x;\n\t\t\tscale[ 1 ] = spriteScale.y;\n\n\t\t\tvar fogType = 0;\n\n\t\t\tif ( scene.fog && material.fog ) {\n\n\t\t\t\tfogType = sceneFogType;\n\n\t\t\t}\n\n\t\t\tif ( oldFogType !== fogType ) {\n\n\t\t\t\tgl.uniform1i( uniforms.fogType, fogType );\n\t\t\t\toldFogType = fogType;\n\n\t\t\t}\n\n\t\t\tif ( material.map !== null ) {\n\n\t\t\t\tgl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y );\n\t\t\t\tgl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y );\n\n\t\t\t} else {\n\n\t\t\t\tgl.uniform2f( uniforms.uvOffset, 0, 0 );\n\t\t\t\tgl.uniform2f( uniforms.uvScale, 1, 1 );\n\n\t\t\t}\n\n\t\t\tgl.uniform1f( uniforms.opacity, material.opacity );\n\t\t\tgl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b );\n\n\t\t\tgl.uniform1f( uniforms.rotation, material.rotation );\n\t\t\tgl.uniform2fv( uniforms.scale, scale );\n\n\t\t\tstate.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );\n\t\t\tstate.setDepthTest( material.depthTest );\n\t\t\tstate.setDepthWrite( material.depthWrite );\n\n\t\t\tif ( material.map ) {\n\n\t\t\t\trenderer.setTexture2D( material.map, 0 );\n\n\t\t\t} else {\n\n\t\t\t\trenderer.setTexture2D( texture, 0 );\n\n\t\t\t}\n\n\t\t\tgl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );\n\n\t\t}\n\n\t\t// restore gl\n\n\t\tstate.enable( gl.CULL_FACE );\n\n\t\trenderer.resetGLState();\n\n\t};\n\n\tfunction createProgram() {\n\n\t\tvar program = gl.createProgram();\n\n\t\tvar vertexShader = gl.createShader( gl.VERTEX_SHADER );\n\t\tvar fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );\n\n\t\tgl.shaderSource( vertexShader, [\n\n\t\t\t'precision ' + renderer.getPrecision() + ' float;',\n\n\t\t\t'uniform mat4 modelViewMatrix;',\n\t\t\t'uniform mat4 projectionMatrix;',\n\t\t\t'uniform float rotation;',\n\t\t\t'uniform vec2 scale;',\n\t\t\t'uniform vec2 uvOffset;',\n\t\t\t'uniform vec2 uvScale;',\n\n\t\t\t'attribute vec2 position;',\n\t\t\t'attribute vec2 uv;',\n\n\t\t\t'varying vec2 vUV;',\n\n\t\t\t'void main() {',\n\n\t\t\t\t'vUV = uvOffset + uv * uvScale;',\n\n\t\t\t\t'vec2 alignedPosition = position * scale;',\n\n\t\t\t\t'vec2 rotatedPosition;',\n\t\t\t\t'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;',\n\t\t\t\t'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;',\n\n\t\t\t\t'vec4 finalPosition;',\n\n\t\t\t\t'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );',\n\t\t\t\t'finalPosition.xy += rotatedPosition;',\n\t\t\t\t'finalPosition = projectionMatrix * finalPosition;',\n\n\t\t\t\t'gl_Position = finalPosition;',\n\n\t\t\t'}'\n\n\t\t].join( '\\n' ) );\n\n\t\tgl.shaderSource( fragmentShader, [\n\n\t\t\t'precision ' + renderer.getPrecision() + ' float;',\n\n\t\t\t'uniform vec3 color;',\n\t\t\t'uniform sampler2D map;',\n\t\t\t'uniform float opacity;',\n\n\t\t\t'uniform int fogType;',\n\t\t\t'uniform vec3 fogColor;',\n\t\t\t'uniform float fogDensity;',\n\t\t\t'uniform float fogNear;',\n\t\t\t'uniform float fogFar;',\n\t\t\t'uniform float alphaTest;',\n\n\t\t\t'varying vec2 vUV;',\n\n\t\t\t'void main() {',\n\n\t\t\t\t'vec4 texture = texture2D( map, vUV );',\n\n\t\t\t\t'if ( texture.a < alphaTest ) discard;',\n\n\t\t\t\t'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );',\n\n\t\t\t\t'if ( fogType > 0 ) {',\n\n\t\t\t\t\t'float depth = gl_FragCoord.z / gl_FragCoord.w;',\n\t\t\t\t\t'float fogFactor = 0.0;',\n\n\t\t\t\t\t'if ( fogType == 1 ) {',\n\n\t\t\t\t\t\t'fogFactor = smoothstep( fogNear, fogFar, depth );',\n\n\t\t\t\t\t'} else {',\n\n\t\t\t\t\t\t'const float LOG2 = 1.442695;',\n\t\t\t\t\t\t'fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );',\n\t\t\t\t\t\t'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );',\n\n\t\t\t\t\t'}',\n\n\t\t\t\t\t'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );',\n\n\t\t\t\t'}',\n\n\t\t\t'}'\n\n\t\t].join( '\\n' ) );\n\n\t\tgl.compileShader( vertexShader );\n\t\tgl.compileShader( fragmentShader );\n\n\t\tgl.attachShader( program, vertexShader );\n\t\tgl.attachShader( program, fragmentShader );\n\n\t\tgl.linkProgram( program );\n\n\t\treturn program;\n\n\t}\n\n\tfunction painterSortStable( a, b ) {\n\n\t\tif ( a.renderOrder !== b.renderOrder ) {\n\n\t\t\treturn a.renderOrder - b.renderOrder;\n\n\t\t} else if ( a.z !== b.z ) {\n\n\t\t\treturn b.z - a.z;\n\n\t\t} else {\n\n\t\t\treturn b.id - a.id;\n\n\t\t}\n\n\t}\n\n}\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author alteredq / http://alteredqualia.com/\n */\n\nvar materialId = 0;\n\nfunction Material() {\n\n\tObject.defineProperty( this, 'id', { value: materialId ++ } );\n\n\tthis.uuid = _Math.generateUUID();\n\n\tthis.name = '';\n\tthis.type = 'Material';\n\n\tthis.fog = true;\n\tthis.lights = true;\n\n\tthis.blending = NormalBlending;\n\tthis.side = FrontSide;\n\tthis.shading = SmoothShading; // THREE.FlatShading, THREE.SmoothShading\n\tthis.vertexColors = NoColors; // THREE.NoColors, THREE.VertexColors, THREE.FaceColors\n\n\tthis.opacity = 1;\n\tthis.transparent = false;\n\n\tthis.blendSrc = SrcAlphaFactor;\n\tthis.blendDst = OneMinusSrcAlphaFactor;\n\tthis.blendEquation = AddEquation;\n\tthis.blendSrcAlpha = null;\n\tthis.blendDstAlpha = null;\n\tthis.blendEquationAlpha = null;\n\n\tthis.depthFunc = LessEqualDepth;\n\tthis.depthTest = true;\n\tthis.depthWrite = true;\n\n\tthis.clippingPlanes = null;\n\tthis.clipIntersection = false;\n\tthis.clipShadows = false;\n\n\tthis.colorWrite = true;\n\n\tthis.precision = null; // override the renderer's default precision for this material\n\n\tthis.polygonOffset = false;\n\tthis.polygonOffsetFactor = 0;\n\tthis.polygonOffsetUnits = 0;\n\n\tthis.alphaTest = 0;\n\tthis.premultipliedAlpha = false;\n\n\tthis.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer\n\n\tthis.visible = true;\n\n\tthis._needsUpdate = true;\n\n}\n\nMaterial.prototype = {\n\n\tconstructor: Material,\n\n\tisMaterial: true,\n\n\tget needsUpdate() {\n\n\t\treturn this._needsUpdate;\n\n\t},\n\n\tset needsUpdate( value ) {\n\n\t\tif ( value === true ) this.update();\n\t\tthis._needsUpdate = value;\n\n\t},\n\n\tsetValues: function ( values ) {\n\n\t\tif ( values === undefined ) return;\n\n\t\tfor ( var key in values ) {\n\n\t\t\tvar newValue = values[ key ];\n\n\t\t\tif ( newValue === undefined ) {\n\n\t\t\t\tconsole.warn( \"THREE.Material: '\" + key + \"' parameter is undefined.\" );\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tvar currentValue = this[ key ];\n\n\t\t\tif ( currentValue === undefined ) {\n\n\t\t\t\tconsole.warn( \"THREE.\" + this.type + \": '\" + key + \"' is not a property of this material.\" );\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tif ( currentValue && currentValue.isColor ) {\n\n\t\t\t\tcurrentValue.set( newValue );\n\n\t\t\t} else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {\n\n\t\t\t\tcurrentValue.copy( newValue );\n\n\t\t\t} else if ( key === 'overdraw' ) {\n\n\t\t\t\t// ensure overdraw is backwards-compatible with legacy boolean type\n\t\t\t\tthis[ key ] = Number( newValue );\n\n\t\t\t} else {\n\n\t\t\t\tthis[ key ] = newValue;\n\n\t\t\t}\n\n\t\t}\n\n\t},\n\n\ttoJSON: function ( meta ) {\n\n\t\tvar isRoot = meta === undefined;\n\n\t\tif ( isRoot ) {\n\n\t\t\tmeta = {\n\t\t\t\ttextures: {},\n\t\t\t\timages: {}\n\t\t\t};\n\n\t\t}\n\n\t\tvar data = {\n\t\t\tmetadata: {\n\t\t\t\tversion: 4.4,\n\t\t\t\ttype: 'Material',\n\t\t\t\tgenerator: 'Material.toJSON'\n\t\t\t}\n\t\t};\n\n\t\t// standard Material serialization\n\t\tdata.uuid = this.uuid;\n\t\tdata.type = this.type;\n\n\t\tif ( this.name !== '' ) data.name = this.name;\n\n\t\tif ( this.color && this.color.isColor ) data.color = this.color.getHex();\n\n\t\tif ( this.roughness !== undefined ) data.roughness = this.roughness;\n\t\tif ( this.metalness !== undefined ) data.metalness = this.metalness;\n\n\t\tif ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();\n\t\tif ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();\n\t\tif ( this.shininess !== undefined ) data.shininess = this.shininess;\n\t\tif ( this.clearCoat !== undefined ) data.clearCoat = this.clearCoat;\n\t\tif ( this.clearCoatRoughness !== undefined ) data.clearCoatRoughness = this.clearCoatRoughness;\n\n\t\tif ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;\n\t\tif ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;\n\t\tif ( this.lightMap && this.lightMap.isTexture ) data.lightMap = this.lightMap.toJSON( meta ).uuid;\n\t\tif ( this.bumpMap && this.bumpMap.isTexture ) {\n\n\t\t\tdata.bumpMap = this.bumpMap.toJSON( meta ).uuid;\n\t\t\tdata.bumpScale = this.bumpScale;\n\n\t\t}\n\t\tif ( this.normalMap && this.normalMap.isTexture ) {\n\n\t\t\tdata.normalMap = this.normalMap.toJSON( meta ).uuid;\n\t\t\tdata.normalScale = this.normalScale.toArray();\n\n\t\t}\n\t\tif ( this.displacementMap && this.displacementMap.isTexture ) {\n\n\t\t\tdata.displacementMap = this.displacementMap.toJSON( meta ).uuid;\n\t\t\tdata.displacementScale = this.displacementScale;\n\t\t\tdata.displacementBias = this.displacementBias;\n\n\t\t}\n\t\tif ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;\n\t\tif ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;\n\n\t\tif ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;\n\t\tif ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;\n\n\t\tif ( this.envMap && this.envMap.isTexture ) {\n\n\t\t\tdata.envMap = this.envMap.toJSON( meta ).uuid;\n\t\t\tdata.reflectivity = this.reflectivity; // Scale behind envMap\n\n\t\t}\n\n\t\tif ( this.gradientMap && this.gradientMap.isTexture ) {\n\n\t\t\tdata.gradientMap = this.gradientMap.toJSON( meta ).uuid;\n\n\t\t}\n\n\t\tif ( this.size !== undefined ) data.size = this.size;\n\t\tif ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;\n\n\t\tif ( this.blending !== NormalBlending ) data.blending = this.blending;\n\t\tif ( this.shading !== SmoothShading ) data.shading = this.shading;\n\t\tif ( this.side !== FrontSide ) data.side = this.side;\n\t\tif ( this.vertexColors !== NoColors ) data.vertexColors = this.vertexColors;\n\n\t\tif ( this.opacity < 1 ) data.opacity = this.opacity;\n\t\tif ( this.transparent === true ) data.transparent = this.transparent;\n\n\t\tdata.depthFunc = this.depthFunc;\n\t\tdata.depthTest = this.depthTest;\n\t\tdata.depthWrite = this.depthWrite;\n\n\t\tif ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;\n\t\tif ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha;\n\t\tif ( this.wireframe === true ) data.wireframe = this.wireframe;\n\t\tif ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;\n\t\tif ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;\n\t\tif ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;\n\n\t\tdata.skinning = this.skinning;\n\t\tdata.morphTargets = this.morphTargets;\n\n\t\t// TODO: Copied from Object3D.toJSON\n\n\t\tfunction extractFromCache( cache ) {\n\n\t\t\tvar values = [];\n\n\t\t\tfor ( var key in cache ) {\n\n\t\t\t\tvar data = cache[ key ];\n\t\t\t\tdelete data.metadata;\n\t\t\t\tvalues.push( data );\n\n\t\t\t}\n\n\t\t\treturn values;\n\n\t\t}\n\n\t\tif ( isRoot ) {\n\n\t\t\tvar textures = extractFromCache( meta.textures );\n\t\t\tvar images = extractFromCache( meta.images );\n\n\t\t\tif ( textures.length > 0 ) data.textures = textures;\n\t\t\tif ( images.length > 0 ) data.images = images;\n\n\t\t}\n\n\t\treturn data;\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor().copy( this );\n\n\t},\n\n\tcopy: function ( source ) {\n\n\t\tthis.name = source.name;\n\n\t\tthis.fog = source.fog;\n\t\tthis.lights = source.lights;\n\n\t\tthis.blending = source.blending;\n\t\tthis.side = source.side;\n\t\tthis.shading = source.shading;\n\t\tthis.vertexColors = source.vertexColors;\n\n\t\tthis.opacity = source.opacity;\n\t\tthis.transparent = source.transparent;\n\n\t\tthis.blendSrc = source.blendSrc;\n\t\tthis.blendDst = source.blendDst;\n\t\tthis.blendEquation = source.blendEquation;\n\t\tthis.blendSrcAlpha = source.blendSrcAlpha;\n\t\tthis.blendDstAlpha = source.blendDstAlpha;\n\t\tthis.blendEquationAlpha = source.blendEquationAlpha;\n\n\t\tthis.depthFunc = source.depthFunc;\n\t\tthis.depthTest = source.depthTest;\n\t\tthis.depthWrite = source.depthWrite;\n\n\t\tthis.colorWrite = source.colorWrite;\n\n\t\tthis.precision = source.precision;\n\n\t\tthis.polygonOffset = source.polygonOffset;\n\t\tthis.polygonOffsetFactor = source.polygonOffsetFactor;\n\t\tthis.polygonOffsetUnits = source.polygonOffsetUnits;\n\n\t\tthis.alphaTest = source.alphaTest;\n\n\t\tthis.premultipliedAlpha = source.premultipliedAlpha;\n\n\t\tthis.overdraw = source.overdraw;\n\n\t\tthis.visible = source.visible;\n\t\tthis.clipShadows = source.clipShadows;\n\t\tthis.clipIntersection = source.clipIntersection;\n\n\t\tvar srcPlanes = source.clippingPlanes,\n\t\t\tdstPlanes = null;\n\n\t\tif ( srcPlanes !== null ) {\n\n\t\t\tvar n = srcPlanes.length;\n\t\t\tdstPlanes = new Array( n );\n\n\t\t\tfor ( var i = 0; i !== n; ++ i )\n\t\t\t\tdstPlanes[ i ] = srcPlanes[ i ].clone();\n\n\t\t}\n\n\t\tthis.clippingPlanes = dstPlanes;\n\n\t\treturn this;\n\n\t},\n\n\tupdate: function () {\n\n\t\tthis.dispatchEvent( { type: 'update' } );\n\n\t},\n\n\tdispose: function () {\n\n\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t}\n\n};\n\nObject.assign( Material.prototype, EventDispatcher.prototype );\n\n/**\n * @author alteredq / http://alteredqualia.com/\n *\n * parameters = {\n * defines: { \"label\" : \"value\" },\n * uniforms: { \"parameter1\": { value: 1.0 }, \"parameter2\": { value2: 2 } },\n *\n * fragmentShader: ,\n * vertexShader: ,\n *\n * wireframe: ,\n * wireframeLinewidth: ,\n *\n * lights: ,\n *\n * skinning: ,\n * morphTargets: ,\n * morphNormals: \n * }\n */\n\nfunction ShaderMaterial( parameters ) {\n\n\tMaterial.call( this );\n\n\tthis.type = 'ShaderMaterial';\n\n\tthis.defines = {};\n\tthis.uniforms = {};\n\n\tthis.vertexShader = 'void main() {\\n\\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\\n}';\n\tthis.fragmentShader = 'void main() {\\n\\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\\n}';\n\n\tthis.linewidth = 1;\n\n\tthis.wireframe = false;\n\tthis.wireframeLinewidth = 1;\n\n\tthis.fog = false; // set to use scene fog\n\tthis.lights = false; // set to use scene lights\n\tthis.clipping = false; // set to use user-defined clipping planes\n\n\tthis.skinning = false; // set to use skinning attribute streams\n\tthis.morphTargets = false; // set to use morph targets\n\tthis.morphNormals = false; // set to use morph normals\n\n\tthis.extensions = {\n\t\tderivatives: false, // set to use derivatives\n\t\tfragDepth: false, // set to use fragment depth values\n\t\tdrawBuffers: false, // set to use draw buffers\n\t\tshaderTextureLOD: false // set to use shader texture LOD\n\t};\n\n\t// When rendered geometry doesn't include these attributes but the material does,\n\t// use these default values in WebGL. This avoids errors when buffer data is missing.\n\tthis.defaultAttributeValues = {\n\t\t'color': [ 1, 1, 1 ],\n\t\t'uv': [ 0, 0 ],\n\t\t'uv2': [ 0, 0 ]\n\t};\n\n\tthis.index0AttributeName = undefined;\n\n\tif ( parameters !== undefined ) {\n\n\t\tif ( parameters.attributes !== undefined ) {\n\n\t\t\tconsole.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' );\n\n\t\t}\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n}\n\nShaderMaterial.prototype = Object.create( Material.prototype );\nShaderMaterial.prototype.constructor = ShaderMaterial;\n\nShaderMaterial.prototype.isShaderMaterial = true;\n\nShaderMaterial.prototype.copy = function ( source ) {\n\n\tMaterial.prototype.copy.call( this, source );\n\n\tthis.fragmentShader = source.fragmentShader;\n\tthis.vertexShader = source.vertexShader;\n\n\tthis.uniforms = UniformsUtils.clone( source.uniforms );\n\n\tthis.defines = source.defines;\n\n\tthis.wireframe = source.wireframe;\n\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\n\tthis.lights = source.lights;\n\tthis.clipping = source.clipping;\n\n\tthis.skinning = source.skinning;\n\n\tthis.morphTargets = source.morphTargets;\n\tthis.morphNormals = source.morphNormals;\n\n\tthis.extensions = source.extensions;\n\n\treturn this;\n\n};\n\nShaderMaterial.prototype.toJSON = function ( meta ) {\n\n\tvar data = Material.prototype.toJSON.call( this, meta );\n\n\tdata.uniforms = this.uniforms;\n\tdata.vertexShader = this.vertexShader;\n\tdata.fragmentShader = this.fragmentShader;\n\n\treturn data;\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author alteredq / http://alteredqualia.com/\n * @author bhouston / https://clara.io\n * @author WestLangley / http://github.com/WestLangley\n *\n * parameters = {\n *\n * opacity: ,\n *\n * map: new THREE.Texture( ),\n *\n * alphaMap: new THREE.Texture( ),\n *\n * displacementMap: new THREE.Texture( ),\n * displacementScale: ,\n * displacementBias: ,\n *\n * wireframe: ,\n * wireframeLinewidth: \n * }\n */\n\nfunction MeshDepthMaterial( parameters ) {\n\n\tMaterial.call( this );\n\n\tthis.type = 'MeshDepthMaterial';\n\n\tthis.depthPacking = BasicDepthPacking;\n\n\tthis.skinning = false;\n\tthis.morphTargets = false;\n\n\tthis.map = null;\n\n\tthis.alphaMap = null;\n\n\tthis.displacementMap = null;\n\tthis.displacementScale = 1;\n\tthis.displacementBias = 0;\n\n\tthis.wireframe = false;\n\tthis.wireframeLinewidth = 1;\n\n\tthis.fog = false;\n\tthis.lights = false;\n\n\tthis.setValues( parameters );\n\n}\n\nMeshDepthMaterial.prototype = Object.create( Material.prototype );\nMeshDepthMaterial.prototype.constructor = MeshDepthMaterial;\n\nMeshDepthMaterial.prototype.isMeshDepthMaterial = true;\n\nMeshDepthMaterial.prototype.copy = function ( source ) {\n\n\tMaterial.prototype.copy.call( this, source );\n\n\tthis.depthPacking = source.depthPacking;\n\n\tthis.skinning = source.skinning;\n\tthis.morphTargets = source.morphTargets;\n\n\tthis.map = source.map;\n\n\tthis.alphaMap = source.alphaMap;\n\n\tthis.displacementMap = source.displacementMap;\n\tthis.displacementScale = source.displacementScale;\n\tthis.displacementBias = source.displacementBias;\n\n\tthis.wireframe = source.wireframe;\n\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\n\treturn this;\n\n};\n\n/**\n * @author bhouston / http://clara.io\n * @author WestLangley / http://github.com/WestLangley\n */\n\nfunction Box3( min, max ) {\n\n\tthis.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity );\n\tthis.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity );\n\n}\n\nBox3.prototype = {\n\n\tconstructor: Box3,\n\n\tisBox3: true,\n\n\tset: function ( min, max ) {\n\n\t\tthis.min.copy( min );\n\t\tthis.max.copy( max );\n\n\t\treturn this;\n\n\t},\n\n\tsetFromArray: function ( array ) {\n\n\t\tvar minX = + Infinity;\n\t\tvar minY = + Infinity;\n\t\tvar minZ = + Infinity;\n\n\t\tvar maxX = - Infinity;\n\t\tvar maxY = - Infinity;\n\t\tvar maxZ = - Infinity;\n\n\t\tfor ( var i = 0, l = array.length; i < l; i += 3 ) {\n\n\t\t\tvar x = array[ i ];\n\t\t\tvar y = array[ i + 1 ];\n\t\t\tvar z = array[ i + 2 ];\n\n\t\t\tif ( x < minX ) minX = x;\n\t\t\tif ( y < minY ) minY = y;\n\t\t\tif ( z < minZ ) minZ = z;\n\n\t\t\tif ( x > maxX ) maxX = x;\n\t\t\tif ( y > maxY ) maxY = y;\n\t\t\tif ( z > maxZ ) maxZ = z;\n\n\t\t}\n\n\t\tthis.min.set( minX, minY, minZ );\n\t\tthis.max.set( maxX, maxY, maxZ );\n\n\t\treturn this;\n\n\t},\n\n\tsetFromBufferAttribute: function ( attribute ) {\n\n\t\tvar minX = + Infinity;\n\t\tvar minY = + Infinity;\n\t\tvar minZ = + Infinity;\n\n\t\tvar maxX = - Infinity;\n\t\tvar maxY = - Infinity;\n\t\tvar maxZ = - Infinity;\n\n\t\tfor ( var i = 0, l = attribute.count; i < l; i ++ ) {\n\n\t\t\tvar x = attribute.getX( i );\n\t\t\tvar y = attribute.getY( i );\n\t\t\tvar z = attribute.getZ( i );\n\n\t\t\tif ( x < minX ) minX = x;\n\t\t\tif ( y < minY ) minY = y;\n\t\t\tif ( z < minZ ) minZ = z;\n\n\t\t\tif ( x > maxX ) maxX = x;\n\t\t\tif ( y > maxY ) maxY = y;\n\t\t\tif ( z > maxZ ) maxZ = z;\n\n\t\t}\n\n\t\tthis.min.set( minX, minY, minZ );\n\t\tthis.max.set( maxX, maxY, maxZ );\n\n\t\treturn this;\n\n\t},\n\n\tsetFromPoints: function ( points ) {\n\n\t\tthis.makeEmpty();\n\n\t\tfor ( var i = 0, il = points.length; i < il; i ++ ) {\n\n\t\t\tthis.expandByPoint( points[ i ] );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tsetFromCenterAndSize: function () {\n\n\t\tvar v1 = new Vector3();\n\n\t\treturn function setFromCenterAndSize( center, size ) {\n\n\t\t\tvar halfSize = v1.copy( size ).multiplyScalar( 0.5 );\n\n\t\t\tthis.min.copy( center ).sub( halfSize );\n\t\t\tthis.max.copy( center ).add( halfSize );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\tsetFromObject: function ( object ) {\n\n\t\tthis.makeEmpty();\n\n\t\treturn this.expandByObject( object );\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor().copy( this );\n\n\t},\n\n\tcopy: function ( box ) {\n\n\t\tthis.min.copy( box.min );\n\t\tthis.max.copy( box.max );\n\n\t\treturn this;\n\n\t},\n\n\tmakeEmpty: function () {\n\n\t\tthis.min.x = this.min.y = this.min.z = + Infinity;\n\t\tthis.max.x = this.max.y = this.max.z = - Infinity;\n\n\t\treturn this;\n\n\t},\n\n\tisEmpty: function () {\n\n\t\t// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes\n\n\t\treturn ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );\n\n\t},\n\n\tgetCenter: function ( optionalTarget ) {\n\n\t\tvar result = optionalTarget || new Vector3();\n\t\treturn this.isEmpty() ? result.set( 0, 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );\n\n\t},\n\n\tgetSize: function ( optionalTarget ) {\n\n\t\tvar result = optionalTarget || new Vector3();\n\t\treturn this.isEmpty() ? result.set( 0, 0, 0 ) : result.subVectors( this.max, this.min );\n\n\t},\n\n\texpandByPoint: function ( point ) {\n\n\t\tthis.min.min( point );\n\t\tthis.max.max( point );\n\n\t\treturn this;\n\n\t},\n\n\texpandByVector: function ( vector ) {\n\n\t\tthis.min.sub( vector );\n\t\tthis.max.add( vector );\n\n\t\treturn this;\n\n\t},\n\n\texpandByScalar: function ( scalar ) {\n\n\t\tthis.min.addScalar( - scalar );\n\t\tthis.max.addScalar( scalar );\n\n\t\treturn this;\n\n\t},\n\n\texpandByObject: function () {\n\n\t\t// Computes the world-axis-aligned bounding box of an object (including its children),\n\t\t// accounting for both the object's, and children's, world transforms\n\n\t\tvar v1 = new Vector3();\n\n\t\treturn function expandByObject( object ) {\n\n\t\t\tvar scope = this;\n\n\t\t\tobject.updateMatrixWorld( true );\n\n\t\t\tobject.traverse( function ( node ) {\n\n\t\t\t\tvar i, l;\n\n\t\t\t\tvar geometry = node.geometry;\n\n\t\t\t\tif ( geometry !== undefined ) {\n\n\t\t\t\t\tif ( geometry.isGeometry ) {\n\n\t\t\t\t\t\tvar vertices = geometry.vertices;\n\n\t\t\t\t\t\tfor ( i = 0, l = vertices.length; i < l; i ++ ) {\n\n\t\t\t\t\t\t\tv1.copy( vertices[ i ] );\n\t\t\t\t\t\t\tv1.applyMatrix4( node.matrixWorld );\n\n\t\t\t\t\t\t\tscope.expandByPoint( v1 );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else if ( geometry.isBufferGeometry ) {\n\n\t\t\t\t\t\tvar attribute = geometry.attributes.position;\n\n\t\t\t\t\t\tif ( attribute !== undefined ) {\n\n\t\t\t\t\t\t\tfor ( i = 0, l = attribute.count; i < l; i ++ ) {\n\n\t\t\t\t\t\t\t\tv1.fromBufferAttribute( attribute, i ).applyMatrix4( node.matrixWorld );\n\n\t\t\t\t\t\t\t\tscope.expandByPoint( v1 );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\tcontainsPoint: function ( point ) {\n\n\t\treturn point.x < this.min.x || point.x > this.max.x ||\n\t\t\tpoint.y < this.min.y || point.y > this.max.y ||\n\t\t\tpoint.z < this.min.z || point.z > this.max.z ? false : true;\n\n\t},\n\n\tcontainsBox: function ( box ) {\n\n\t\treturn this.min.x <= box.min.x && box.max.x <= this.max.x &&\n\t\t\tthis.min.y <= box.min.y && box.max.y <= this.max.y &&\n\t\t\tthis.min.z <= box.min.z && box.max.z <= this.max.z;\n\n\t},\n\n\tgetParameter: function ( point, optionalTarget ) {\n\n\t\t// This can potentially have a divide by zero if the box\n\t\t// has a size dimension of 0.\n\n\t\tvar result = optionalTarget || new Vector3();\n\n\t\treturn result.set(\n\t\t\t( point.x - this.min.x ) / ( this.max.x - this.min.x ),\n\t\t\t( point.y - this.min.y ) / ( this.max.y - this.min.y ),\n\t\t\t( point.z - this.min.z ) / ( this.max.z - this.min.z )\n\t\t);\n\n\t},\n\n\tintersectsBox: function ( box ) {\n\n\t\t// using 6 splitting planes to rule out intersections.\n\t\treturn box.max.x < this.min.x || box.min.x > this.max.x ||\n\t\t\tbox.max.y < this.min.y || box.min.y > this.max.y ||\n\t\t\tbox.max.z < this.min.z || box.min.z > this.max.z ? false : true;\n\n\t},\n\n\tintersectsSphere: ( function () {\n\n\t\tvar closestPoint;\n\n\t\treturn function intersectsSphere( sphere ) {\n\n\t\t\tif ( closestPoint === undefined ) closestPoint = new Vector3();\n\n\t\t\t// Find the point on the AABB closest to the sphere center.\n\t\t\tthis.clampPoint( sphere.center, closestPoint );\n\n\t\t\t// If that point is inside the sphere, the AABB and sphere intersect.\n\t\t\treturn closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );\n\n\t\t};\n\n\t} )(),\n\n\tintersectsPlane: function ( plane ) {\n\n\t\t// We compute the minimum and maximum dot product values. If those values\n\t\t// are on the same side (back or front) of the plane, then there is no intersection.\n\n\t\tvar min, max;\n\n\t\tif ( plane.normal.x > 0 ) {\n\n\t\t\tmin = plane.normal.x * this.min.x;\n\t\t\tmax = plane.normal.x * this.max.x;\n\n\t\t} else {\n\n\t\t\tmin = plane.normal.x * this.max.x;\n\t\t\tmax = plane.normal.x * this.min.x;\n\n\t\t}\n\n\t\tif ( plane.normal.y > 0 ) {\n\n\t\t\tmin += plane.normal.y * this.min.y;\n\t\t\tmax += plane.normal.y * this.max.y;\n\n\t\t} else {\n\n\t\t\tmin += plane.normal.y * this.max.y;\n\t\t\tmax += plane.normal.y * this.min.y;\n\n\t\t}\n\n\t\tif ( plane.normal.z > 0 ) {\n\n\t\t\tmin += plane.normal.z * this.min.z;\n\t\t\tmax += plane.normal.z * this.max.z;\n\n\t\t} else {\n\n\t\t\tmin += plane.normal.z * this.max.z;\n\t\t\tmax += plane.normal.z * this.min.z;\n\n\t\t}\n\n\t\treturn ( min <= plane.constant && max >= plane.constant );\n\n\t},\n\n\tclampPoint: function ( point, optionalTarget ) {\n\n\t\tvar result = optionalTarget || new Vector3();\n\t\treturn result.copy( point ).clamp( this.min, this.max );\n\n\t},\n\n\tdistanceToPoint: function () {\n\n\t\tvar v1 = new Vector3();\n\n\t\treturn function distanceToPoint( point ) {\n\n\t\t\tvar clampedPoint = v1.copy( point ).clamp( this.min, this.max );\n\t\t\treturn clampedPoint.sub( point ).length();\n\n\t\t};\n\n\t}(),\n\n\tgetBoundingSphere: function () {\n\n\t\tvar v1 = new Vector3();\n\n\t\treturn function getBoundingSphere( optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Sphere();\n\n\t\t\tthis.getCenter( result.center );\n\n\t\t\tresult.radius = this.getSize( v1 ).length() * 0.5;\n\n\t\t\treturn result;\n\n\t\t};\n\n\t}(),\n\n\tintersect: function ( box ) {\n\n\t\tthis.min.max( box.min );\n\t\tthis.max.min( box.max );\n\n\t\t// ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.\n\t\tif( this.isEmpty() ) this.makeEmpty();\n\n\t\treturn this;\n\n\t},\n\n\tunion: function ( box ) {\n\n\t\tthis.min.min( box.min );\n\t\tthis.max.max( box.max );\n\n\t\treturn this;\n\n\t},\n\n\tapplyMatrix4: function () {\n\n\t\tvar points = [\n\t\t\tnew Vector3(),\n\t\t\tnew Vector3(),\n\t\t\tnew Vector3(),\n\t\t\tnew Vector3(),\n\t\t\tnew Vector3(),\n\t\t\tnew Vector3(),\n\t\t\tnew Vector3(),\n\t\t\tnew Vector3()\n\t\t];\n\n\t\treturn function applyMatrix4( matrix ) {\n\n\t\t\t// transform of empty box is an empty box.\n\t\t\tif( this.isEmpty() ) return this;\n\n\t\t\t// NOTE: I am using a binary pattern to specify all 2^3 combinations below\n\t\t\tpoints[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000\n\t\t\tpoints[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001\n\t\t\tpoints[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010\n\t\t\tpoints[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011\n\t\t\tpoints[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100\n\t\t\tpoints[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101\n\t\t\tpoints[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110\n\t\t\tpoints[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix );\t// 111\n\n\t\t\tthis.setFromPoints( points );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\ttranslate: function ( offset ) {\n\n\t\tthis.min.add( offset );\n\t\tthis.max.add( offset );\n\n\t\treturn this;\n\n\t},\n\n\tequals: function ( box ) {\n\n\t\treturn box.min.equals( this.min ) && box.max.equals( this.max );\n\n\t}\n\n};\n\n/**\n * @author bhouston / http://clara.io\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction Sphere( center, radius ) {\n\n\tthis.center = ( center !== undefined ) ? center : new Vector3();\n\tthis.radius = ( radius !== undefined ) ? radius : 0;\n\n}\n\nSphere.prototype = {\n\n\tconstructor: Sphere,\n\n\tset: function ( center, radius ) {\n\n\t\tthis.center.copy( center );\n\t\tthis.radius = radius;\n\n\t\treturn this;\n\n\t},\n\n\tsetFromPoints: function () {\n\n\t\tvar box;\n\n\t\treturn function setFromPoints( points, optionalCenter ) {\n\n\t\t\tif ( box === undefined ) box = new Box3(); // see #10547\n\n\t\t\tvar center = this.center;\n\n\t\t\tif ( optionalCenter !== undefined ) {\n\n\t\t\t\tcenter.copy( optionalCenter );\n\n\t\t\t} else {\n\n\t\t\t\tbox.setFromPoints( points ).getCenter( center );\n\n\t\t\t}\n\n\t\t\tvar maxRadiusSq = 0;\n\n\t\t\tfor ( var i = 0, il = points.length; i < il; i ++ ) {\n\n\t\t\t\tmaxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );\n\n\t\t\t}\n\n\t\t\tthis.radius = Math.sqrt( maxRadiusSq );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\tclone: function () {\n\n\t\treturn new this.constructor().copy( this );\n\n\t},\n\n\tcopy: function ( sphere ) {\n\n\t\tthis.center.copy( sphere.center );\n\t\tthis.radius = sphere.radius;\n\n\t\treturn this;\n\n\t},\n\n\tempty: function () {\n\n\t\treturn ( this.radius <= 0 );\n\n\t},\n\n\tcontainsPoint: function ( point ) {\n\n\t\treturn ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );\n\n\t},\n\n\tdistanceToPoint: function ( point ) {\n\n\t\treturn ( point.distanceTo( this.center ) - this.radius );\n\n\t},\n\n\tintersectsSphere: function ( sphere ) {\n\n\t\tvar radiusSum = this.radius + sphere.radius;\n\n\t\treturn sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );\n\n\t},\n\n\tintersectsBox: function ( box ) {\n\n\t\treturn box.intersectsSphere( this );\n\n\t},\n\n\tintersectsPlane: function ( plane ) {\n\n\t\t// We use the following equation to compute the signed distance from\n\t\t// the center of the sphere to the plane.\n\t\t//\n\t\t// distance = q * n - d\n\t\t//\n\t\t// If this distance is greater than the radius of the sphere,\n\t\t// then there is no intersection.\n\n\t\treturn Math.abs( this.center.dot( plane.normal ) - plane.constant ) <= this.radius;\n\n\t},\n\n\tclampPoint: function ( point, optionalTarget ) {\n\n\t\tvar deltaLengthSq = this.center.distanceToSquared( point );\n\n\t\tvar result = optionalTarget || new Vector3();\n\n\t\tresult.copy( point );\n\n\t\tif ( deltaLengthSq > ( this.radius * this.radius ) ) {\n\n\t\t\tresult.sub( this.center ).normalize();\n\t\t\tresult.multiplyScalar( this.radius ).add( this.center );\n\n\t\t}\n\n\t\treturn result;\n\n\t},\n\n\tgetBoundingBox: function ( optionalTarget ) {\n\n\t\tvar box = optionalTarget || new Box3();\n\n\t\tbox.set( this.center, this.center );\n\t\tbox.expandByScalar( this.radius );\n\n\t\treturn box;\n\n\t},\n\n\tapplyMatrix4: function ( matrix ) {\n\n\t\tthis.center.applyMatrix4( matrix );\n\t\tthis.radius = this.radius * matrix.getMaxScaleOnAxis();\n\n\t\treturn this;\n\n\t},\n\n\ttranslate: function ( offset ) {\n\n\t\tthis.center.add( offset );\n\n\t\treturn this;\n\n\t},\n\n\tequals: function ( sphere ) {\n\n\t\treturn sphere.center.equals( this.center ) && ( sphere.radius === this.radius );\n\n\t}\n\n};\n\n/**\n * @author alteredq / http://alteredqualia.com/\n * @author WestLangley / http://github.com/WestLangley\n * @author bhouston / http://clara.io\n * @author tschw\n */\n\nfunction Matrix3() {\n\n\tthis.elements = new Float32Array( [\n\n\t\t1, 0, 0,\n\t\t0, 1, 0,\n\t\t0, 0, 1\n\n\t] );\n\n\tif ( arguments.length > 0 ) {\n\n\t\tconsole.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );\n\n\t}\n\n}\n\nMatrix3.prototype = {\n\n\tconstructor: Matrix3,\n\n\tisMatrix3: true,\n\n\tset: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {\n\n\t\tvar te = this.elements;\n\n\t\tte[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;\n\t\tte[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;\n\t\tte[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;\n\n\t\treturn this;\n\n\t},\n\n\tidentity: function () {\n\n\t\tthis.set(\n\n\t\t\t1, 0, 0,\n\t\t\t0, 1, 0,\n\t\t\t0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor().fromArray( this.elements );\n\n\t},\n\n\tcopy: function ( m ) {\n\n\t\tvar me = m.elements;\n\n\t\tthis.set(\n\n\t\t\tme[ 0 ], me[ 3 ], me[ 6 ],\n\t\t\tme[ 1 ], me[ 4 ], me[ 7 ],\n\t\t\tme[ 2 ], me[ 5 ], me[ 8 ]\n\n\t\t);\n\n\t\treturn this;\n\n\t},\n\n\tsetFromMatrix4: function( m ) {\n\n\t\tvar me = m.elements;\n\n\t\tthis.set(\n\n\t\t\tme[ 0 ], me[ 4 ], me[ 8 ],\n\t\t\tme[ 1 ], me[ 5 ], me[ 9 ],\n\t\t\tme[ 2 ], me[ 6 ], me[ 10 ]\n\n\t\t);\n\n\t\treturn this;\n\n\t},\n\n\tapplyToBufferAttribute: function () {\n\n\t\tvar v1;\n\n\t\treturn function applyToBufferAttribute( attribute ) {\n\n\t\t\tif ( v1 === undefined ) v1 = new Vector3();\n\n\t\t\tfor ( var i = 0, l = attribute.count; i < l; i ++ ) {\n\n\t\t\t\tv1.x = attribute.getX( i );\n\t\t\t\tv1.y = attribute.getY( i );\n\t\t\t\tv1.z = attribute.getZ( i );\n\n\t\t\t\tv1.applyMatrix3( this );\n\n\t\t\t\tattribute.setXYZ( i, v1.x, v1.y, v1.z );\n\n\t\t\t}\n\n\t\t\treturn attribute;\n\n\t\t};\n\n\t}(),\n\n\tmultiplyScalar: function ( s ) {\n\n\t\tvar te = this.elements;\n\n\t\tte[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;\n\t\tte[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;\n\t\tte[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;\n\n\t\treturn this;\n\n\t},\n\n\tdeterminant: function () {\n\n\t\tvar te = this.elements;\n\n\t\tvar a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],\n\t\t\td = te[ 3 ], e = te[ 4 ], f = te[ 5 ],\n\t\t\tg = te[ 6 ], h = te[ 7 ], i = te[ 8 ];\n\n\t\treturn a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;\n\n\t},\n\n\tgetInverse: function ( matrix, throwOnDegenerate ) {\n\n\t\tif ( matrix && matrix.isMatrix4 ) {\n\n\t\t\tconsole.error( \"THREE.Matrix3.getInverse no longer takes a Matrix4 argument.\" );\n\n\t\t}\n\n\t\tvar me = matrix.elements,\n\t\t\tte = this.elements,\n\n\t\t\tn11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ],\n\t\t\tn12 = me[ 3 ], n22 = me[ 4 ], n32 = me[ 5 ],\n\t\t\tn13 = me[ 6 ], n23 = me[ 7 ], n33 = me[ 8 ],\n\n\t\t\tt11 = n33 * n22 - n32 * n23,\n\t\t\tt12 = n32 * n13 - n33 * n12,\n\t\t\tt13 = n23 * n12 - n22 * n13,\n\n\t\t\tdet = n11 * t11 + n21 * t12 + n31 * t13;\n\n\t\tif ( det === 0 ) {\n\n\t\t\tvar msg = \"THREE.Matrix3.getInverse(): can't invert matrix, determinant is 0\";\n\n\t\t\tif ( throwOnDegenerate === true ) {\n\n\t\t\t\tthrow new Error( msg );\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( msg );\n\n\t\t\t}\n\n\t\t\treturn this.identity();\n\t\t}\n\n\t\tvar detInv = 1 / det;\n\n\t\tte[ 0 ] = t11 * detInv;\n\t\tte[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;\n\t\tte[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;\n\n\t\tte[ 3 ] = t12 * detInv;\n\t\tte[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;\n\t\tte[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;\n\n\t\tte[ 6 ] = t13 * detInv;\n\t\tte[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;\n\t\tte[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;\n\n\t\treturn this;\n\n\t},\n\n\ttranspose: function () {\n\n\t\tvar tmp, m = this.elements;\n\n\t\ttmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;\n\t\ttmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;\n\t\ttmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;\n\n\t\treturn this;\n\n\t},\n\n\tgetNormalMatrix: function ( matrix4 ) {\n\n\t\treturn this.setFromMatrix4( matrix4 ).getInverse( this ).transpose();\n\n\t},\n\n\ttransposeIntoArray: function ( r ) {\n\n\t\tvar m = this.elements;\n\n\t\tr[ 0 ] = m[ 0 ];\n\t\tr[ 1 ] = m[ 3 ];\n\t\tr[ 2 ] = m[ 6 ];\n\t\tr[ 3 ] = m[ 1 ];\n\t\tr[ 4 ] = m[ 4 ];\n\t\tr[ 5 ] = m[ 7 ];\n\t\tr[ 6 ] = m[ 2 ];\n\t\tr[ 7 ] = m[ 5 ];\n\t\tr[ 8 ] = m[ 8 ];\n\n\t\treturn this;\n\n\t},\n\n\tfromArray: function ( array, offset ) {\n\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tfor( var i = 0; i < 9; i ++ ) {\n\n\t\t\tthis.elements[ i ] = array[ i + offset ];\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\ttoArray: function ( array, offset ) {\n\n\t\tif ( array === undefined ) array = [];\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tvar te = this.elements;\n\n\t\tarray[ offset ] = te[ 0 ];\n\t\tarray[ offset + 1 ] = te[ 1 ];\n\t\tarray[ offset + 2 ] = te[ 2 ];\n\n\t\tarray[ offset + 3 ] = te[ 3 ];\n\t\tarray[ offset + 4 ] = te[ 4 ];\n\t\tarray[ offset + 5 ] = te[ 5 ];\n\n\t\tarray[ offset + 6 ] = te[ 6 ];\n\t\tarray[ offset + 7 ] = te[ 7 ];\n\t\tarray[ offset + 8 ] = te[ 8 ];\n\n\t\treturn array;\n\n\t}\n\n};\n\n/**\n * @author bhouston / http://clara.io\n */\n\nfunction Plane( normal, constant ) {\n\n\tthis.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 );\n\tthis.constant = ( constant !== undefined ) ? constant : 0;\n\n}\n\nPlane.prototype = {\n\n\tconstructor: Plane,\n\n\tset: function ( normal, constant ) {\n\n\t\tthis.normal.copy( normal );\n\t\tthis.constant = constant;\n\n\t\treturn this;\n\n\t},\n\n\tsetComponents: function ( x, y, z, w ) {\n\n\t\tthis.normal.set( x, y, z );\n\t\tthis.constant = w;\n\n\t\treturn this;\n\n\t},\n\n\tsetFromNormalAndCoplanarPoint: function ( normal, point ) {\n\n\t\tthis.normal.copy( normal );\n\t\tthis.constant = - point.dot( this.normal );\t// must be this.normal, not normal, as this.normal is normalized\n\n\t\treturn this;\n\n\t},\n\n\tsetFromCoplanarPoints: function () {\n\n\t\tvar v1 = new Vector3();\n\t\tvar v2 = new Vector3();\n\n\t\treturn function setFromCoplanarPoints( a, b, c ) {\n\n\t\t\tvar normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize();\n\n\t\t\t// Q: should an error be thrown if normal is zero (e.g. degenerate plane)?\n\n\t\t\tthis.setFromNormalAndCoplanarPoint( normal, a );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\tclone: function () {\n\n\t\treturn new this.constructor().copy( this );\n\n\t},\n\n\tcopy: function ( plane ) {\n\n\t\tthis.normal.copy( plane.normal );\n\t\tthis.constant = plane.constant;\n\n\t\treturn this;\n\n\t},\n\n\tnormalize: function () {\n\n\t\t// Note: will lead to a divide by zero if the plane is invalid.\n\n\t\tvar inverseNormalLength = 1.0 / this.normal.length();\n\t\tthis.normal.multiplyScalar( inverseNormalLength );\n\t\tthis.constant *= inverseNormalLength;\n\n\t\treturn this;\n\n\t},\n\n\tnegate: function () {\n\n\t\tthis.constant *= - 1;\n\t\tthis.normal.negate();\n\n\t\treturn this;\n\n\t},\n\n\tdistanceToPoint: function ( point ) {\n\n\t\treturn this.normal.dot( point ) + this.constant;\n\n\t},\n\n\tdistanceToSphere: function ( sphere ) {\n\n\t\treturn this.distanceToPoint( sphere.center ) - sphere.radius;\n\n\t},\n\n\tprojectPoint: function ( point, optionalTarget ) {\n\n\t\treturn this.orthoPoint( point, optionalTarget ).sub( point ).negate();\n\n\t},\n\n\torthoPoint: function ( point, optionalTarget ) {\n\n\t\tvar perpendicularMagnitude = this.distanceToPoint( point );\n\n\t\tvar result = optionalTarget || new Vector3();\n\t\treturn result.copy( this.normal ).multiplyScalar( perpendicularMagnitude );\n\n\t},\n\n\tintersectLine: function () {\n\n\t\tvar v1 = new Vector3();\n\n\t\treturn function intersectLine( line, optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\n\t\t\tvar direction = line.delta( v1 );\n\n\t\t\tvar denominator = this.normal.dot( direction );\n\n\t\t\tif ( denominator === 0 ) {\n\n\t\t\t\t// line is coplanar, return origin\n\t\t\t\tif ( this.distanceToPoint( line.start ) === 0 ) {\n\n\t\t\t\t\treturn result.copy( line.start );\n\n\t\t\t\t}\n\n\t\t\t\t// Unsure if this is the correct method to handle this case.\n\t\t\t\treturn undefined;\n\n\t\t\t}\n\n\t\t\tvar t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;\n\n\t\t\tif ( t < 0 || t > 1 ) {\n\n\t\t\t\treturn undefined;\n\n\t\t\t}\n\n\t\t\treturn result.copy( direction ).multiplyScalar( t ).add( line.start );\n\n\t\t};\n\n\t}(),\n\n\tintersectsLine: function ( line ) {\n\n\t\t// Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.\n\n\t\tvar startSign = this.distanceToPoint( line.start );\n\t\tvar endSign = this.distanceToPoint( line.end );\n\n\t\treturn ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );\n\n\t},\n\n\tintersectsBox: function ( box ) {\n\n\t\treturn box.intersectsPlane( this );\n\n\t},\n\n\tintersectsSphere: function ( sphere ) {\n\n\t\treturn sphere.intersectsPlane( this );\n\n\t},\n\n\tcoplanarPoint: function ( optionalTarget ) {\n\n\t\tvar result = optionalTarget || new Vector3();\n\t\treturn result.copy( this.normal ).multiplyScalar( - this.constant );\n\n\t},\n\n\tapplyMatrix4: function () {\n\n\t\tvar v1 = new Vector3();\n\t\tvar m1 = new Matrix3();\n\n\t\treturn function applyMatrix4( matrix, optionalNormalMatrix ) {\n\n\t\t\tvar referencePoint = this.coplanarPoint( v1 ).applyMatrix4( matrix );\n\n\t\t\t// transform normal based on theory here:\n\t\t\t// http://www.songho.ca/opengl/gl_normaltransform.html\n\t\t\tvar normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix );\n\t\t\tvar normal = this.normal.applyMatrix3( normalMatrix ).normalize();\n\n\t\t\t// recalculate constant (like in setFromNormalAndCoplanarPoint)\n\t\t\tthis.constant = - referencePoint.dot( normal );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\ttranslate: function ( offset ) {\n\n\t\tthis.constant = this.constant - offset.dot( this.normal );\n\n\t\treturn this;\n\n\t},\n\n\tequals: function ( plane ) {\n\n\t\treturn plane.normal.equals( this.normal ) && ( plane.constant === this.constant );\n\n\t}\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author alteredq / http://alteredqualia.com/\n * @author bhouston / http://clara.io\n */\n\nfunction Frustum( p0, p1, p2, p3, p4, p5 ) {\n\n\tthis.planes = [\n\n\t\t( p0 !== undefined ) ? p0 : new Plane(),\n\t\t( p1 !== undefined ) ? p1 : new Plane(),\n\t\t( p2 !== undefined ) ? p2 : new Plane(),\n\t\t( p3 !== undefined ) ? p3 : new Plane(),\n\t\t( p4 !== undefined ) ? p4 : new Plane(),\n\t\t( p5 !== undefined ) ? p5 : new Plane()\n\n\t];\n\n}\n\nFrustum.prototype = {\n\n\tconstructor: Frustum,\n\n\tset: function ( p0, p1, p2, p3, p4, p5 ) {\n\n\t\tvar planes = this.planes;\n\n\t\tplanes[ 0 ].copy( p0 );\n\t\tplanes[ 1 ].copy( p1 );\n\t\tplanes[ 2 ].copy( p2 );\n\t\tplanes[ 3 ].copy( p3 );\n\t\tplanes[ 4 ].copy( p4 );\n\t\tplanes[ 5 ].copy( p5 );\n\n\t\treturn this;\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor().copy( this );\n\n\t},\n\n\tcopy: function ( frustum ) {\n\n\t\tvar planes = this.planes;\n\n\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\tplanes[ i ].copy( frustum.planes[ i ] );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tsetFromMatrix: function ( m ) {\n\n\t\tvar planes = this.planes;\n\t\tvar me = m.elements;\n\t\tvar me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];\n\t\tvar me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];\n\t\tvar me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];\n\t\tvar me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];\n\n\t\tplanes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();\n\t\tplanes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();\n\t\tplanes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();\n\t\tplanes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();\n\t\tplanes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();\n\t\tplanes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();\n\n\t\treturn this;\n\n\t},\n\n\tintersectsObject: function () {\n\n\t\tvar sphere = new Sphere();\n\n\t\treturn function intersectsObject( object ) {\n\n\t\t\tvar geometry = object.geometry;\n\n\t\t\tif ( geometry.boundingSphere === null )\n\t\t\t\tgeometry.computeBoundingSphere();\n\n\t\t\tsphere.copy( geometry.boundingSphere )\n\t\t\t\t.applyMatrix4( object.matrixWorld );\n\n\t\t\treturn this.intersectsSphere( sphere );\n\n\t\t};\n\n\t}(),\n\n\tintersectsSprite: function () {\n\n\t\tvar sphere = new Sphere();\n\n\t\treturn function intersectsSprite( sprite ) {\n\n\t\t\tsphere.center.set( 0, 0, 0 );\n\t\t\tsphere.radius = 0.7071067811865476;\n\t\t\tsphere.applyMatrix4( sprite.matrixWorld );\n\n\t\t\treturn this.intersectsSphere( sphere );\n\n\t\t};\n\n\t}(),\n\n\tintersectsSphere: function ( sphere ) {\n\n\t\tvar planes = this.planes;\n\t\tvar center = sphere.center;\n\t\tvar negRadius = - sphere.radius;\n\n\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\tvar distance = planes[ i ].distanceToPoint( center );\n\n\t\t\tif ( distance < negRadius ) {\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn true;\n\n\t},\n\n\tintersectsBox: function () {\n\n\t\tvar p1 = new Vector3(),\n\t\t\tp2 = new Vector3();\n\n\t\treturn function intersectsBox( box ) {\n\n\t\t\tvar planes = this.planes;\n\n\t\t\tfor ( var i = 0; i < 6 ; i ++ ) {\n\n\t\t\t\tvar plane = planes[ i ];\n\n\t\t\t\tp1.x = plane.normal.x > 0 ? box.min.x : box.max.x;\n\t\t\t\tp2.x = plane.normal.x > 0 ? box.max.x : box.min.x;\n\t\t\t\tp1.y = plane.normal.y > 0 ? box.min.y : box.max.y;\n\t\t\t\tp2.y = plane.normal.y > 0 ? box.max.y : box.min.y;\n\t\t\t\tp1.z = plane.normal.z > 0 ? box.min.z : box.max.z;\n\t\t\t\tp2.z = plane.normal.z > 0 ? box.max.z : box.min.z;\n\n\t\t\t\tvar d1 = plane.distanceToPoint( p1 );\n\t\t\t\tvar d2 = plane.distanceToPoint( p2 );\n\n\t\t\t\t// if both outside plane, no intersection\n\n\t\t\t\tif ( d1 < 0 && d2 < 0 ) {\n\n\t\t\t\t\treturn false;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn true;\n\n\t\t};\n\n\t}(),\n\n\n\tcontainsPoint: function ( point ) {\n\n\t\tvar planes = this.planes;\n\n\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\tif ( planes[ i ].distanceToPoint( point ) < 0 ) {\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n};\n\n/**\n * @author alteredq / http://alteredqualia.com/\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction WebGLShadowMap( _renderer, _lights, _objects, capabilities ) {\n\n\tvar _gl = _renderer.context,\n\t_state = _renderer.state,\n\t_frustum = new Frustum(),\n\t_projScreenMatrix = new Matrix4(),\n\n\t_lightShadows = _lights.shadows,\n\n\t_shadowMapSize = new Vector2(),\n\t_maxShadowMapSize = new Vector2( capabilities.maxTextureSize, capabilities.maxTextureSize ),\n\n\t_lookTarget = new Vector3(),\n\t_lightPositionWorld = new Vector3(),\n\n\t_renderList = [],\n\n\t_MorphingFlag = 1,\n\t_SkinningFlag = 2,\n\n\t_NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1,\n\n\t_depthMaterials = new Array( _NumberOfMaterialVariants ),\n\t_distanceMaterials = new Array( _NumberOfMaterialVariants ),\n\n\t_materialCache = {};\n\n\tvar cubeDirections = [\n\t\tnew Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),\n\t\tnew Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )\n\t];\n\n\tvar cubeUps = [\n\t\tnew Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),\n\t\tnew Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ),\tnew Vector3( 0, 0, - 1 )\n\t];\n\n\tvar cube2DViewPorts = [\n\t\tnew Vector4(), new Vector4(), new Vector4(),\n\t\tnew Vector4(), new Vector4(), new Vector4()\n\t];\n\n\t// init\n\n\tvar depthMaterialTemplate = new MeshDepthMaterial();\n\tdepthMaterialTemplate.depthPacking = RGBADepthPacking;\n\tdepthMaterialTemplate.clipping = true;\n\n\tvar distanceShader = ShaderLib[ \"distanceRGBA\" ];\n\tvar distanceUniforms = UniformsUtils.clone( distanceShader.uniforms );\n\n\tfor ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) {\n\n\t\tvar useMorphing = ( i & _MorphingFlag ) !== 0;\n\t\tvar useSkinning = ( i & _SkinningFlag ) !== 0;\n\n\t\tvar depthMaterial = depthMaterialTemplate.clone();\n\t\tdepthMaterial.morphTargets = useMorphing;\n\t\tdepthMaterial.skinning = useSkinning;\n\n\t\t_depthMaterials[ i ] = depthMaterial;\n\n\t\tvar distanceMaterial = new ShaderMaterial( {\n\t\t\tdefines: {\n\t\t\t\t'USE_SHADOWMAP': ''\n\t\t\t},\n\t\t\tuniforms: distanceUniforms,\n\t\t\tvertexShader: distanceShader.vertexShader,\n\t\t\tfragmentShader: distanceShader.fragmentShader,\n\t\t\tmorphTargets: useMorphing,\n\t\t\tskinning: useSkinning,\n\t\t\tclipping: true\n\t\t} );\n\n\t\t_distanceMaterials[ i ] = distanceMaterial;\n\n\t}\n\n\t//\n\n\tvar scope = this;\n\n\tthis.enabled = false;\n\n\tthis.autoUpdate = true;\n\tthis.needsUpdate = false;\n\n\tthis.type = PCFShadowMap;\n\n\tthis.renderReverseSided = true;\n\tthis.renderSingleSided = true;\n\n\tthis.render = function ( scene, camera ) {\n\n\t\tif ( scope.enabled === false ) return;\n\t\tif ( scope.autoUpdate === false && scope.needsUpdate === false ) return;\n\n\t\tif ( _lightShadows.length === 0 ) return;\n\n\t\t// Set GL state for depth map.\n\t\t_state.buffers.color.setClear( 1, 1, 1, 1 );\n\t\t_state.disable( _gl.BLEND );\n\t\t_state.setDepthTest( true );\n\t\t_state.setScissorTest( false );\n\n\t\t// render depth map\n\n\t\tvar faceCount, isPointLight;\n\n\t\tfor ( var i = 0, il = _lightShadows.length; i < il; i ++ ) {\n\n\t\t\tvar light = _lightShadows[ i ];\n\t\t\tvar shadow = light.shadow;\n\n\t\t\tif ( shadow === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tvar shadowCamera = shadow.camera;\n\n\t\t\t_shadowMapSize.copy( shadow.mapSize );\n\t\t\t_shadowMapSize.min( _maxShadowMapSize );\n\n\t\t\tif ( light && light.isPointLight ) {\n\n\t\t\t\tfaceCount = 6;\n\t\t\t\tisPointLight = true;\n\n\t\t\t\tvar vpWidth = _shadowMapSize.x;\n\t\t\t\tvar vpHeight = _shadowMapSize.y;\n\n\t\t\t\t// These viewports map a cube-map onto a 2D texture with the\n\t\t\t\t// following orientation:\n\t\t\t\t//\n\t\t\t\t// xzXZ\n\t\t\t\t// y Y\n\t\t\t\t//\n\t\t\t\t// X - Positive x direction\n\t\t\t\t// x - Negative x direction\n\t\t\t\t// Y - Positive y direction\n\t\t\t\t// y - Negative y direction\n\t\t\t\t// Z - Positive z direction\n\t\t\t\t// z - Negative z direction\n\n\t\t\t\t// positive X\n\t\t\t\tcube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight );\n\t\t\t\t// negative X\n\t\t\t\tcube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight );\n\t\t\t\t// positive Z\n\t\t\t\tcube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight );\n\t\t\t\t// negative Z\n\t\t\t\tcube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight );\n\t\t\t\t// positive Y\n\t\t\t\tcube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight );\n\t\t\t\t// negative Y\n\t\t\t\tcube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight );\n\n\t\t\t\t_shadowMapSize.x *= 4.0;\n\t\t\t\t_shadowMapSize.y *= 2.0;\n\n\t\t\t} else {\n\n\t\t\t\tfaceCount = 1;\n\t\t\t\tisPointLight = false;\n\n\t\t\t}\n\n\t\t\tif ( shadow.map === null ) {\n\n\t\t\t\tvar pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat };\n\n\t\t\t\tshadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );\n\n\t\t\t\tshadowCamera.updateProjectionMatrix();\n\n\t\t\t}\n\n\t\t\tif ( shadow.isSpotLightShadow ) {\n\n\t\t\t\tshadow.update( light );\n\n\t\t\t}\n\n\t\t\t// TODO (abelnation / sam-g-steel): is this needed?\n\t\t\tif (shadow && shadow.isRectAreaLightShadow ) {\n\n\t\t\t\tshadow.update( light );\n\n\t\t\t}\n\n\t\t\tvar shadowMap = shadow.map;\n\t\t\tvar shadowMatrix = shadow.matrix;\n\n\t\t\t_lightPositionWorld.setFromMatrixPosition( light.matrixWorld );\n\t\t\tshadowCamera.position.copy( _lightPositionWorld );\n\n\t\t\t_renderer.setRenderTarget( shadowMap );\n\t\t\t_renderer.clear();\n\n\t\t\t// render shadow map for each cube face (if omni-directional) or\n\t\t\t// run a single pass if not\n\n\t\t\tfor ( var face = 0; face < faceCount; face ++ ) {\n\n\t\t\t\tif ( isPointLight ) {\n\n\t\t\t\t\t_lookTarget.copy( shadowCamera.position );\n\t\t\t\t\t_lookTarget.add( cubeDirections[ face ] );\n\t\t\t\t\tshadowCamera.up.copy( cubeUps[ face ] );\n\t\t\t\t\tshadowCamera.lookAt( _lookTarget );\n\n\t\t\t\t\tvar vpDimensions = cube2DViewPorts[ face ];\n\t\t\t\t\t_state.viewport( vpDimensions );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t_lookTarget.setFromMatrixPosition( light.target.matrixWorld );\n\t\t\t\t\tshadowCamera.lookAt( _lookTarget );\n\n\t\t\t\t}\n\n\t\t\t\tshadowCamera.updateMatrixWorld();\n\t\t\t\tshadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld );\n\n\t\t\t\t// compute shadow matrix\n\n\t\t\t\tshadowMatrix.set(\n\t\t\t\t\t0.5, 0.0, 0.0, 0.5,\n\t\t\t\t\t0.0, 0.5, 0.0, 0.5,\n\t\t\t\t\t0.0, 0.0, 0.5, 0.5,\n\t\t\t\t\t0.0, 0.0, 0.0, 1.0\n\t\t\t\t);\n\n\t\t\t\tshadowMatrix.multiply( shadowCamera.projectionMatrix );\n\t\t\t\tshadowMatrix.multiply( shadowCamera.matrixWorldInverse );\n\n\t\t\t\t// update camera matrices and frustum\n\n\t\t\t\t_projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );\n\t\t\t\t_frustum.setFromMatrix( _projScreenMatrix );\n\n\t\t\t\t// set object matrices & frustum culling\n\n\t\t\t\t_renderList.length = 0;\n\n\t\t\t\tprojectObject( scene, camera, shadowCamera );\n\n\t\t\t\t// render shadow map\n\t\t\t\t// render regular objects\n\n\t\t\t\tfor ( var j = 0, jl = _renderList.length; j < jl; j ++ ) {\n\n\t\t\t\t\tvar object = _renderList[ j ];\n\t\t\t\t\tvar geometry = _objects.update( object );\n\t\t\t\t\tvar material = object.material;\n\n\t\t\t\t\tif ( material && material.isMultiMaterial ) {\n\n\t\t\t\t\t\tvar groups = geometry.groups;\n\t\t\t\t\t\tvar materials = material.materials;\n\n\t\t\t\t\t\tfor ( var k = 0, kl = groups.length; k < kl; k ++ ) {\n\n\t\t\t\t\t\t\tvar group = groups[ k ];\n\t\t\t\t\t\t\tvar groupMaterial = materials[ group.materialIndex ];\n\n\t\t\t\t\t\t\tif ( groupMaterial.visible === true ) {\n\n\t\t\t\t\t\t\t\tvar depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld );\n\t\t\t\t\t\t\t\t_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tvar depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld );\n\t\t\t\t\t\t_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Restore GL state.\n\t\tvar clearColor = _renderer.getClearColor(),\n\t\tclearAlpha = _renderer.getClearAlpha();\n\t\t_renderer.setClearColor( clearColor, clearAlpha );\n\n\t\tscope.needsUpdate = false;\n\n\t};\n\n\tfunction getDepthMaterial( object, material, isPointLight, lightPositionWorld ) {\n\n\t\tvar geometry = object.geometry;\n\n\t\tvar result = null;\n\n\t\tvar materialVariants = _depthMaterials;\n\t\tvar customMaterial = object.customDepthMaterial;\n\n\t\tif ( isPointLight ) {\n\n\t\t\tmaterialVariants = _distanceMaterials;\n\t\t\tcustomMaterial = object.customDistanceMaterial;\n\n\t\t}\n\n\t\tif ( ! customMaterial ) {\n\n\t\t\tvar useMorphing = false;\n\n\t\t\tif ( material.morphTargets ) {\n\n\t\t\t\tif ( geometry && geometry.isBufferGeometry ) {\n\n\t\t\t\t\tuseMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0;\n\n\t\t\t\t} else if ( geometry && geometry.isGeometry ) {\n\n\t\t\t\t\tuseMorphing = geometry.morphTargets && geometry.morphTargets.length > 0;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tvar useSkinning = object.isSkinnedMesh && material.skinning;\n\n\t\t\tvar variantIndex = 0;\n\n\t\t\tif ( useMorphing ) variantIndex |= _MorphingFlag;\n\t\t\tif ( useSkinning ) variantIndex |= _SkinningFlag;\n\n\t\t\tresult = materialVariants[ variantIndex ];\n\n\t\t} else {\n\n\t\t\tresult = customMaterial;\n\n\t\t}\n\n\t\tif ( _renderer.localClippingEnabled &&\n\t\t\t material.clipShadows === true &&\n\t\t\t\tmaterial.clippingPlanes.length !== 0 ) {\n\n\t\t\t// in this case we need a unique material instance reflecting the\n\t\t\t// appropriate state\n\n\t\t\tvar keyA = result.uuid, keyB = material.uuid;\n\n\t\t\tvar materialsForVariant = _materialCache[ keyA ];\n\n\t\t\tif ( materialsForVariant === undefined ) {\n\n\t\t\t\tmaterialsForVariant = {};\n\t\t\t\t_materialCache[ keyA ] = materialsForVariant;\n\n\t\t\t}\n\n\t\t\tvar cachedMaterial = materialsForVariant[ keyB ];\n\n\t\t\tif ( cachedMaterial === undefined ) {\n\n\t\t\t\tcachedMaterial = result.clone();\n\t\t\t\tmaterialsForVariant[ keyB ] = cachedMaterial;\n\n\t\t\t}\n\n\t\t\tresult = cachedMaterial;\n\n\t\t}\n\n\t\tresult.visible = material.visible;\n\t\tresult.wireframe = material.wireframe;\n\n\t\tvar side = material.side;\n\n\t\tif ( scope.renderSingleSided && side == DoubleSide ) {\n\n\t\t\tside = FrontSide;\n\n\t\t}\n\n\t\tif ( scope.renderReverseSided ) {\n\n\t\t\tif ( side === FrontSide ) side = BackSide;\n\t\t\telse if ( side === BackSide ) side = FrontSide;\n\n\t\t}\n\n\t\tresult.side = side;\n\n\t\tresult.clipShadows = material.clipShadows;\n\t\tresult.clippingPlanes = material.clippingPlanes;\n\n\t\tresult.wireframeLinewidth = material.wireframeLinewidth;\n\t\tresult.linewidth = material.linewidth;\n\n\t\tif ( isPointLight && result.uniforms.lightPos !== undefined ) {\n\n\t\t\tresult.uniforms.lightPos.value.copy( lightPositionWorld );\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n\tfunction projectObject( object, camera, shadowCamera ) {\n\n\t\tif ( object.visible === false ) return;\n\n\t\tvar visible = ( object.layers.mask & camera.layers.mask ) !== 0;\n\n\t\tif ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {\n\n\t\t\tif ( object.castShadow && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) {\n\n\t\t\t\tvar material = object.material;\n\n\t\t\t\tif ( material.visible === true ) {\n\n\t\t\t\t\tobject.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );\n\t\t\t\t\t_renderList.push( object );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar children = object.children;\n\n\t\tfor ( var i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tprojectObject( children[ i ], camera, shadowCamera );\n\n\t\t}\n\n\t}\n\n}\n\n/**\n * @author bhouston / http://clara.io\n */\n\nfunction Ray( origin, direction ) {\n\n\tthis.origin = ( origin !== undefined ) ? origin : new Vector3();\n\tthis.direction = ( direction !== undefined ) ? direction : new Vector3();\n\n}\n\nRay.prototype = {\n\n\tconstructor: Ray,\n\n\tset: function ( origin, direction ) {\n\n\t\tthis.origin.copy( origin );\n\t\tthis.direction.copy( direction );\n\n\t\treturn this;\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor().copy( this );\n\n\t},\n\n\tcopy: function ( ray ) {\n\n\t\tthis.origin.copy( ray.origin );\n\t\tthis.direction.copy( ray.direction );\n\n\t\treturn this;\n\n\t},\n\n\tat: function ( t, optionalTarget ) {\n\n\t\tvar result = optionalTarget || new Vector3();\n\n\t\treturn result.copy( this.direction ).multiplyScalar( t ).add( this.origin );\n\n\t},\n\n\tlookAt: function ( v ) {\n\n\t\tthis.direction.copy( v ).sub( this.origin ).normalize();\n\n\t\treturn this;\n\n\t},\n\n\trecast: function () {\n\n\t\tvar v1 = new Vector3();\n\n\t\treturn function recast( t ) {\n\n\t\t\tthis.origin.copy( this.at( t, v1 ) );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\tclosestPointToPoint: function ( point, optionalTarget ) {\n\n\t\tvar result = optionalTarget || new Vector3();\n\t\tresult.subVectors( point, this.origin );\n\t\tvar directionDistance = result.dot( this.direction );\n\n\t\tif ( directionDistance < 0 ) {\n\n\t\t\treturn result.copy( this.origin );\n\n\t\t}\n\n\t\treturn result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );\n\n\t},\n\n\tdistanceToPoint: function ( point ) {\n\n\t\treturn Math.sqrt( this.distanceSqToPoint( point ) );\n\n\t},\n\n\tdistanceSqToPoint: function () {\n\n\t\tvar v1 = new Vector3();\n\n\t\treturn function distanceSqToPoint( point ) {\n\n\t\t\tvar directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );\n\n\t\t\t// point behind the ray\n\n\t\t\tif ( directionDistance < 0 ) {\n\n\t\t\t\treturn this.origin.distanceToSquared( point );\n\n\t\t\t}\n\n\t\t\tv1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );\n\n\t\t\treturn v1.distanceToSquared( point );\n\n\t\t};\n\n\t}(),\n\n\tdistanceSqToSegment: function () {\n\n\t\tvar segCenter = new Vector3();\n\t\tvar segDir = new Vector3();\n\t\tvar diff = new Vector3();\n\n\t\treturn function distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {\n\n\t\t\t// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h\n\t\t\t// It returns the min distance between the ray and the segment\n\t\t\t// defined by v0 and v1\n\t\t\t// It can also set two optional targets :\n\t\t\t// - The closest point on the ray\n\t\t\t// - The closest point on the segment\n\n\t\t\tsegCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );\n\t\t\tsegDir.copy( v1 ).sub( v0 ).normalize();\n\t\t\tdiff.copy( this.origin ).sub( segCenter );\n\n\t\t\tvar segExtent = v0.distanceTo( v1 ) * 0.5;\n\t\t\tvar a01 = - this.direction.dot( segDir );\n\t\t\tvar b0 = diff.dot( this.direction );\n\t\t\tvar b1 = - diff.dot( segDir );\n\t\t\tvar c = diff.lengthSq();\n\t\t\tvar det = Math.abs( 1 - a01 * a01 );\n\t\t\tvar s0, s1, sqrDist, extDet;\n\n\t\t\tif ( det > 0 ) {\n\n\t\t\t\t// The ray and segment are not parallel.\n\n\t\t\t\ts0 = a01 * b1 - b0;\n\t\t\t\ts1 = a01 * b0 - b1;\n\t\t\t\textDet = segExtent * det;\n\n\t\t\t\tif ( s0 >= 0 ) {\n\n\t\t\t\t\tif ( s1 >= - extDet ) {\n\n\t\t\t\t\t\tif ( s1 <= extDet ) {\n\n\t\t\t\t\t\t\t// region 0\n\t\t\t\t\t\t\t// Minimum at interior points of ray and segment.\n\n\t\t\t\t\t\t\tvar invDet = 1 / det;\n\t\t\t\t\t\t\ts0 *= invDet;\n\t\t\t\t\t\t\ts1 *= invDet;\n\t\t\t\t\t\t\tsqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// region 1\n\n\t\t\t\t\t\t\ts1 = segExtent;\n\t\t\t\t\t\t\ts0 = Math.max( 0, - ( a01 * s1 + b0 ) );\n\t\t\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// region 5\n\n\t\t\t\t\t\ts1 = - segExtent;\n\t\t\t\t\t\ts0 = Math.max( 0, - ( a01 * s1 + b0 ) );\n\t\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( s1 <= - extDet ) {\n\n\t\t\t\t\t\t// region 4\n\n\t\t\t\t\t\ts0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );\n\t\t\t\t\t\ts1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );\n\t\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t\t} else if ( s1 <= extDet ) {\n\n\t\t\t\t\t\t// region 3\n\n\t\t\t\t\t\ts0 = 0;\n\t\t\t\t\t\ts1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );\n\t\t\t\t\t\tsqrDist = s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// region 2\n\n\t\t\t\t\t\ts0 = Math.max( 0, - ( a01 * segExtent + b0 ) );\n\t\t\t\t\t\ts1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );\n\t\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// Ray and segment are parallel.\n\n\t\t\t\ts1 = ( a01 > 0 ) ? - segExtent : segExtent;\n\t\t\t\ts0 = Math.max( 0, - ( a01 * s1 + b0 ) );\n\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t}\n\n\t\t\tif ( optionalPointOnRay ) {\n\n\t\t\t\toptionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin );\n\n\t\t\t}\n\n\t\t\tif ( optionalPointOnSegment ) {\n\n\t\t\t\toptionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter );\n\n\t\t\t}\n\n\t\t\treturn sqrDist;\n\n\t\t};\n\n\t}(),\n\n\tintersectSphere: function () {\n\n\t\tvar v1 = new Vector3();\n\n\t\treturn function intersectSphere( sphere, optionalTarget ) {\n\n\t\t\tv1.subVectors( sphere.center, this.origin );\n\t\t\tvar tca = v1.dot( this.direction );\n\t\t\tvar d2 = v1.dot( v1 ) - tca * tca;\n\t\t\tvar radius2 = sphere.radius * sphere.radius;\n\n\t\t\tif ( d2 > radius2 ) return null;\n\n\t\t\tvar thc = Math.sqrt( radius2 - d2 );\n\n\t\t\t// t0 = first intersect point - entrance on front of sphere\n\t\t\tvar t0 = tca - thc;\n\n\t\t\t// t1 = second intersect point - exit point on back of sphere\n\t\t\tvar t1 = tca + thc;\n\n\t\t\t// test to see if both t0 and t1 are behind the ray - if so, return null\n\t\t\tif ( t0 < 0 && t1 < 0 ) return null;\n\n\t\t\t// test to see if t0 is behind the ray:\n\t\t\t// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,\n\t\t\t// in order to always return an intersect point that is in front of the ray.\n\t\t\tif ( t0 < 0 ) return this.at( t1, optionalTarget );\n\n\t\t\t// else t0 is in front of the ray, so return the first collision point scaled by t0\n\t\t\treturn this.at( t0, optionalTarget );\n\n\t\t};\n\n\t}(),\n\n\tintersectsSphere: function ( sphere ) {\n\n\t\treturn this.distanceToPoint( sphere.center ) <= sphere.radius;\n\n\t},\n\n\tdistanceToPlane: function ( plane ) {\n\n\t\tvar denominator = plane.normal.dot( this.direction );\n\n\t\tif ( denominator === 0 ) {\n\n\t\t\t// line is coplanar, return origin\n\t\t\tif ( plane.distanceToPoint( this.origin ) === 0 ) {\n\n\t\t\t\treturn 0;\n\n\t\t\t}\n\n\t\t\t// Null is preferable to undefined since undefined means.... it is undefined\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\tvar t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;\n\n\t\t// Return if the ray never intersects the plane\n\n\t\treturn t >= 0 ? t : null;\n\n\t},\n\n\tintersectPlane: function ( plane, optionalTarget ) {\n\n\t\tvar t = this.distanceToPlane( plane );\n\n\t\tif ( t === null ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\treturn this.at( t, optionalTarget );\n\n\t},\n\n\n\n\tintersectsPlane: function ( plane ) {\n\n\t\t// check if the ray lies on the plane first\n\n\t\tvar distToPoint = plane.distanceToPoint( this.origin );\n\n\t\tif ( distToPoint === 0 ) {\n\n\t\t\treturn true;\n\n\t\t}\n\n\t\tvar denominator = plane.normal.dot( this.direction );\n\n\t\tif ( denominator * distToPoint < 0 ) {\n\n\t\t\treturn true;\n\n\t\t}\n\n\t\t// ray origin is behind the plane (and is pointing behind it)\n\n\t\treturn false;\n\n\t},\n\n\tintersectBox: function ( box, optionalTarget ) {\n\n\t\tvar tmin, tmax, tymin, tymax, tzmin, tzmax;\n\n\t\tvar invdirx = 1 / this.direction.x,\n\t\t\tinvdiry = 1 / this.direction.y,\n\t\t\tinvdirz = 1 / this.direction.z;\n\n\t\tvar origin = this.origin;\n\n\t\tif ( invdirx >= 0 ) {\n\n\t\t\ttmin = ( box.min.x - origin.x ) * invdirx;\n\t\t\ttmax = ( box.max.x - origin.x ) * invdirx;\n\n\t\t} else {\n\n\t\t\ttmin = ( box.max.x - origin.x ) * invdirx;\n\t\t\ttmax = ( box.min.x - origin.x ) * invdirx;\n\n\t\t}\n\n\t\tif ( invdiry >= 0 ) {\n\n\t\t\ttymin = ( box.min.y - origin.y ) * invdiry;\n\t\t\ttymax = ( box.max.y - origin.y ) * invdiry;\n\n\t\t} else {\n\n\t\t\ttymin = ( box.max.y - origin.y ) * invdiry;\n\t\t\ttymax = ( box.min.y - origin.y ) * invdiry;\n\n\t\t}\n\n\t\tif ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;\n\n\t\t// These lines also handle the case where tmin or tmax is NaN\n\t\t// (result of 0 * Infinity). x !== x returns true if x is NaN\n\n\t\tif ( tymin > tmin || tmin !== tmin ) tmin = tymin;\n\n\t\tif ( tymax < tmax || tmax !== tmax ) tmax = tymax;\n\n\t\tif ( invdirz >= 0 ) {\n\n\t\t\ttzmin = ( box.min.z - origin.z ) * invdirz;\n\t\t\ttzmax = ( box.max.z - origin.z ) * invdirz;\n\n\t\t} else {\n\n\t\t\ttzmin = ( box.max.z - origin.z ) * invdirz;\n\t\t\ttzmax = ( box.min.z - origin.z ) * invdirz;\n\n\t\t}\n\n\t\tif ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;\n\n\t\tif ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;\n\n\t\tif ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;\n\n\t\t//return point closest to the ray (positive side)\n\n\t\tif ( tmax < 0 ) return null;\n\n\t\treturn this.at( tmin >= 0 ? tmin : tmax, optionalTarget );\n\n\t},\n\n\tintersectsBox: ( function () {\n\n\t\tvar v = new Vector3();\n\n\t\treturn function intersectsBox( box ) {\n\n\t\t\treturn this.intersectBox( box, v ) !== null;\n\n\t\t};\n\n\t} )(),\n\n\tintersectTriangle: function () {\n\n\t\t// Compute the offset origin, edges, and normal.\n\t\tvar diff = new Vector3();\n\t\tvar edge1 = new Vector3();\n\t\tvar edge2 = new Vector3();\n\t\tvar normal = new Vector3();\n\n\t\treturn function intersectTriangle( a, b, c, backfaceCulling, optionalTarget ) {\n\n\t\t\t// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h\n\n\t\t\tedge1.subVectors( b, a );\n\t\t\tedge2.subVectors( c, a );\n\t\t\tnormal.crossVectors( edge1, edge2 );\n\n\t\t\t// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,\n\t\t\t// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by\n\t\t\t// |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))\n\t\t\t// |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))\n\t\t\t// |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)\n\t\t\tvar DdN = this.direction.dot( normal );\n\t\t\tvar sign;\n\n\t\t\tif ( DdN > 0 ) {\n\n\t\t\t\tif ( backfaceCulling ) return null;\n\t\t\t\tsign = 1;\n\n\t\t\t} else if ( DdN < 0 ) {\n\n\t\t\t\tsign = - 1;\n\t\t\t\tDdN = - DdN;\n\n\t\t\t} else {\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t\tdiff.subVectors( this.origin, a );\n\t\t\tvar DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) );\n\n\t\t\t// b1 < 0, no intersection\n\t\t\tif ( DdQxE2 < 0 ) {\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t\tvar DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) );\n\n\t\t\t// b2 < 0, no intersection\n\t\t\tif ( DdE1xQ < 0 ) {\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t\t// b1+b2 > 1, no intersection\n\t\t\tif ( DdQxE2 + DdE1xQ > DdN ) {\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t\t// Line intersects triangle, check if ray does.\n\t\t\tvar QdN = - sign * diff.dot( normal );\n\n\t\t\t// t < 0, no intersection\n\t\t\tif ( QdN < 0 ) {\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t\t// Ray intersects triangle.\n\t\t\treturn this.at( QdN / DdN, optionalTarget );\n\n\t\t};\n\n\t}(),\n\n\tapplyMatrix4: function ( matrix4 ) {\n\n\t\tthis.direction.add( this.origin ).applyMatrix4( matrix4 );\n\t\tthis.origin.applyMatrix4( matrix4 );\n\t\tthis.direction.sub( this.origin );\n\t\tthis.direction.normalize();\n\n\t\treturn this;\n\n\t},\n\n\tequals: function ( ray ) {\n\n\t\treturn ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );\n\n\t}\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author WestLangley / http://github.com/WestLangley\n * @author bhouston / http://clara.io\n */\n\nfunction Euler( x, y, z, order ) {\n\n\tthis._x = x || 0;\n\tthis._y = y || 0;\n\tthis._z = z || 0;\n\tthis._order = order || Euler.DefaultOrder;\n\n}\n\nEuler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];\n\nEuler.DefaultOrder = 'XYZ';\n\nEuler.prototype = {\n\n\tconstructor: Euler,\n\n\tisEuler: true,\n\n\tget x () {\n\n\t\treturn this._x;\n\n\t},\n\n\tset x ( value ) {\n\n\t\tthis._x = value;\n\t\tthis.onChangeCallback();\n\n\t},\n\n\tget y () {\n\n\t\treturn this._y;\n\n\t},\n\n\tset y ( value ) {\n\n\t\tthis._y = value;\n\t\tthis.onChangeCallback();\n\n\t},\n\n\tget z () {\n\n\t\treturn this._z;\n\n\t},\n\n\tset z ( value ) {\n\n\t\tthis._z = value;\n\t\tthis.onChangeCallback();\n\n\t},\n\n\tget order () {\n\n\t\treturn this._order;\n\n\t},\n\n\tset order ( value ) {\n\n\t\tthis._order = value;\n\t\tthis.onChangeCallback();\n\n\t},\n\n\tset: function ( x, y, z, order ) {\n\n\t\tthis._x = x;\n\t\tthis._y = y;\n\t\tthis._z = z;\n\t\tthis._order = order || this._order;\n\n\t\tthis.onChangeCallback();\n\n\t\treturn this;\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor( this._x, this._y, this._z, this._order );\n\n\t},\n\n\tcopy: function ( euler ) {\n\n\t\tthis._x = euler._x;\n\t\tthis._y = euler._y;\n\t\tthis._z = euler._z;\n\t\tthis._order = euler._order;\n\n\t\tthis.onChangeCallback();\n\n\t\treturn this;\n\n\t},\n\n\tsetFromRotationMatrix: function ( m, order, update ) {\n\n\t\tvar clamp = _Math.clamp;\n\n\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\n\n\t\tvar te = m.elements;\n\t\tvar m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];\n\t\tvar m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];\n\t\tvar m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];\n\n\t\torder = order || this._order;\n\n\t\tif ( order === 'XYZ' ) {\n\n\t\t\tthis._y = Math.asin( clamp( m13, - 1, 1 ) );\n\n\t\t\tif ( Math.abs( m13 ) < 0.99999 ) {\n\n\t\t\t\tthis._x = Math.atan2( - m23, m33 );\n\t\t\t\tthis._z = Math.atan2( - m12, m11 );\n\n\t\t\t} else {\n\n\t\t\t\tthis._x = Math.atan2( m32, m22 );\n\t\t\t\tthis._z = 0;\n\n\t\t\t}\n\n\t\t} else if ( order === 'YXZ' ) {\n\n\t\t\tthis._x = Math.asin( - clamp( m23, - 1, 1 ) );\n\n\t\t\tif ( Math.abs( m23 ) < 0.99999 ) {\n\n\t\t\t\tthis._y = Math.atan2( m13, m33 );\n\t\t\t\tthis._z = Math.atan2( m21, m22 );\n\n\t\t\t} else {\n\n\t\t\t\tthis._y = Math.atan2( - m31, m11 );\n\t\t\t\tthis._z = 0;\n\n\t\t\t}\n\n\t\t} else if ( order === 'ZXY' ) {\n\n\t\t\tthis._x = Math.asin( clamp( m32, - 1, 1 ) );\n\n\t\t\tif ( Math.abs( m32 ) < 0.99999 ) {\n\n\t\t\t\tthis._y = Math.atan2( - m31, m33 );\n\t\t\t\tthis._z = Math.atan2( - m12, m22 );\n\n\t\t\t} else {\n\n\t\t\t\tthis._y = 0;\n\t\t\t\tthis._z = Math.atan2( m21, m11 );\n\n\t\t\t}\n\n\t\t} else if ( order === 'ZYX' ) {\n\n\t\t\tthis._y = Math.asin( - clamp( m31, - 1, 1 ) );\n\n\t\t\tif ( Math.abs( m31 ) < 0.99999 ) {\n\n\t\t\t\tthis._x = Math.atan2( m32, m33 );\n\t\t\t\tthis._z = Math.atan2( m21, m11 );\n\n\t\t\t} else {\n\n\t\t\t\tthis._x = 0;\n\t\t\t\tthis._z = Math.atan2( - m12, m22 );\n\n\t\t\t}\n\n\t\t} else if ( order === 'YZX' ) {\n\n\t\t\tthis._z = Math.asin( clamp( m21, - 1, 1 ) );\n\n\t\t\tif ( Math.abs( m21 ) < 0.99999 ) {\n\n\t\t\t\tthis._x = Math.atan2( - m23, m22 );\n\t\t\t\tthis._y = Math.atan2( - m31, m11 );\n\n\t\t\t} else {\n\n\t\t\t\tthis._x = 0;\n\t\t\t\tthis._y = Math.atan2( m13, m33 );\n\n\t\t\t}\n\n\t\t} else if ( order === 'XZY' ) {\n\n\t\t\tthis._z = Math.asin( - clamp( m12, - 1, 1 ) );\n\n\t\t\tif ( Math.abs( m12 ) < 0.99999 ) {\n\n\t\t\t\tthis._x = Math.atan2( m32, m22 );\n\t\t\t\tthis._y = Math.atan2( m13, m11 );\n\n\t\t\t} else {\n\n\t\t\t\tthis._x = Math.atan2( - m23, m33 );\n\t\t\t\tthis._y = 0;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order );\n\n\t\t}\n\n\t\tthis._order = order;\n\n\t\tif ( update !== false ) this.onChangeCallback();\n\n\t\treturn this;\n\n\t},\n\n\tsetFromQuaternion: function () {\n\n\t\tvar matrix;\n\n\t\treturn function setFromQuaternion( q, order, update ) {\n\n\t\t\tif ( matrix === undefined ) matrix = new Matrix4();\n\n\t\t\tmatrix.makeRotationFromQuaternion( q );\n\n\t\t\treturn this.setFromRotationMatrix( matrix, order, update );\n\n\t\t};\n\n\t}(),\n\n\tsetFromVector3: function ( v, order ) {\n\n\t\treturn this.set( v.x, v.y, v.z, order || this._order );\n\n\t},\n\n\treorder: function () {\n\n\t\t// WARNING: this discards revolution information -bhouston\n\n\t\tvar q = new Quaternion();\n\n\t\treturn function reorder( newOrder ) {\n\n\t\t\tq.setFromEuler( this );\n\n\t\t\treturn this.setFromQuaternion( q, newOrder );\n\n\t\t};\n\n\t}(),\n\n\tequals: function ( euler ) {\n\n\t\treturn ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );\n\n\t},\n\n\tfromArray: function ( array ) {\n\n\t\tthis._x = array[ 0 ];\n\t\tthis._y = array[ 1 ];\n\t\tthis._z = array[ 2 ];\n\t\tif ( array[ 3 ] !== undefined ) this._order = array[ 3 ];\n\n\t\tthis.onChangeCallback();\n\n\t\treturn this;\n\n\t},\n\n\ttoArray: function ( array, offset ) {\n\n\t\tif ( array === undefined ) array = [];\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tarray[ offset ] = this._x;\n\t\tarray[ offset + 1 ] = this._y;\n\t\tarray[ offset + 2 ] = this._z;\n\t\tarray[ offset + 3 ] = this._order;\n\n\t\treturn array;\n\n\t},\n\n\ttoVector3: function ( optionalResult ) {\n\n\t\tif ( optionalResult ) {\n\n\t\t\treturn optionalResult.set( this._x, this._y, this._z );\n\n\t\t} else {\n\n\t\t\treturn new Vector3( this._x, this._y, this._z );\n\n\t\t}\n\n\t},\n\n\tonChange: function ( callback ) {\n\n\t\tthis.onChangeCallback = callback;\n\n\t\treturn this;\n\n\t},\n\n\tonChangeCallback: function () {}\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction Layers() {\n\n\tthis.mask = 1;\n\n}\n\nLayers.prototype = {\n\n\tconstructor: Layers,\n\n\tset: function ( channel ) {\n\n\t\tthis.mask = 1 << channel;\n\n\t},\n\n\tenable: function ( channel ) {\n\n\t\tthis.mask |= 1 << channel;\n\n\t},\n\n\ttoggle: function ( channel ) {\n\n\t\tthis.mask ^= 1 << channel;\n\n\t},\n\n\tdisable: function ( channel ) {\n\n\t\tthis.mask &= ~ ( 1 << channel );\n\n\t},\n\n\ttest: function ( layers ) {\n\n\t\treturn ( this.mask & layers.mask ) !== 0;\n\n\t}\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author mikael emtinger / http://gomo.se/\n * @author alteredq / http://alteredqualia.com/\n * @author WestLangley / http://github.com/WestLangley\n * @author elephantatwork / www.elephantatwork.ch\n */\n\nvar object3DId = 0;\n\nfunction Object3D() {\n\n\tObject.defineProperty( this, 'id', { value: object3DId ++ } );\n\n\tthis.uuid = _Math.generateUUID();\n\n\tthis.name = '';\n\tthis.type = 'Object3D';\n\n\tthis.parent = null;\n\tthis.children = [];\n\n\tthis.up = Object3D.DefaultUp.clone();\n\n\tvar position = new Vector3();\n\tvar rotation = new Euler();\n\tvar quaternion = new Quaternion();\n\tvar scale = new Vector3( 1, 1, 1 );\n\n\tfunction onRotationChange() {\n\n\t\tquaternion.setFromEuler( rotation, false );\n\n\t}\n\n\tfunction onQuaternionChange() {\n\n\t\trotation.setFromQuaternion( quaternion, undefined, false );\n\n\t}\n\n\trotation.onChange( onRotationChange );\n\tquaternion.onChange( onQuaternionChange );\n\n\tObject.defineProperties( this, {\n\t\tposition: {\n\t\t\tenumerable: true,\n\t\t\tvalue: position\n\t\t},\n\t\trotation: {\n\t\t\tenumerable: true,\n\t\t\tvalue: rotation\n\t\t},\n\t\tquaternion: {\n\t\t\tenumerable: true,\n\t\t\tvalue: quaternion\n\t\t},\n\t\tscale: {\n\t\t\tenumerable: true,\n\t\t\tvalue: scale\n\t\t},\n\t\tmodelViewMatrix: {\n\t\t\tvalue: new Matrix4()\n\t\t},\n\t\tnormalMatrix: {\n\t\t\tvalue: new Matrix3()\n\t\t}\n\t} );\n\n\tthis.matrix = new Matrix4();\n\tthis.matrixWorld = new Matrix4();\n\n\tthis.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;\n\tthis.matrixWorldNeedsUpdate = false;\n\n\tthis.layers = new Layers();\n\tthis.visible = true;\n\n\tthis.castShadow = false;\n\tthis.receiveShadow = false;\n\n\tthis.frustumCulled = true;\n\tthis.renderOrder = 0;\n\n\tthis.userData = {};\n\n\tthis.onBeforeRender = function () {};\n\tthis.onAfterRender = function () {};\n\n}\n\nObject3D.DefaultUp = new Vector3( 0, 1, 0 );\nObject3D.DefaultMatrixAutoUpdate = true;\n\nObject3D.prototype = {\n\n\tconstructor: Object3D,\n\n\tisObject3D: true,\n\n\tapplyMatrix: function ( matrix ) {\n\n\t\tthis.matrix.multiplyMatrices( matrix, this.matrix );\n\n\t\tthis.matrix.decompose( this.position, this.quaternion, this.scale );\n\n\t},\n\n\tsetRotationFromAxisAngle: function ( axis, angle ) {\n\n\t\t// assumes axis is normalized\n\n\t\tthis.quaternion.setFromAxisAngle( axis, angle );\n\n\t},\n\n\tsetRotationFromEuler: function ( euler ) {\n\n\t\tthis.quaternion.setFromEuler( euler, true );\n\n\t},\n\n\tsetRotationFromMatrix: function ( m ) {\n\n\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\n\n\t\tthis.quaternion.setFromRotationMatrix( m );\n\n\t},\n\n\tsetRotationFromQuaternion: function ( q ) {\n\n\t\t// assumes q is normalized\n\n\t\tthis.quaternion.copy( q );\n\n\t},\n\n\trotateOnAxis: function () {\n\n\t\t// rotate object on axis in object space\n\t\t// axis is assumed to be normalized\n\n\t\tvar q1 = new Quaternion();\n\n\t\treturn function rotateOnAxis( axis, angle ) {\n\n\t\t\tq1.setFromAxisAngle( axis, angle );\n\n\t\t\tthis.quaternion.multiply( q1 );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\trotateX: function () {\n\n\t\tvar v1 = new Vector3( 1, 0, 0 );\n\n\t\treturn function rotateX( angle ) {\n\n\t\t\treturn this.rotateOnAxis( v1, angle );\n\n\t\t};\n\n\t}(),\n\n\trotateY: function () {\n\n\t\tvar v1 = new Vector3( 0, 1, 0 );\n\n\t\treturn function rotateY( angle ) {\n\n\t\t\treturn this.rotateOnAxis( v1, angle );\n\n\t\t};\n\n\t}(),\n\n\trotateZ: function () {\n\n\t\tvar v1 = new Vector3( 0, 0, 1 );\n\n\t\treturn function rotateZ( angle ) {\n\n\t\t\treturn this.rotateOnAxis( v1, angle );\n\n\t\t};\n\n\t}(),\n\n\ttranslateOnAxis: function () {\n\n\t\t// translate object by distance along axis in object space\n\t\t// axis is assumed to be normalized\n\n\t\tvar v1 = new Vector3();\n\n\t\treturn function translateOnAxis( axis, distance ) {\n\n\t\t\tv1.copy( axis ).applyQuaternion( this.quaternion );\n\n\t\t\tthis.position.add( v1.multiplyScalar( distance ) );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\ttranslateX: function () {\n\n\t\tvar v1 = new Vector3( 1, 0, 0 );\n\n\t\treturn function translateX( distance ) {\n\n\t\t\treturn this.translateOnAxis( v1, distance );\n\n\t\t};\n\n\t}(),\n\n\ttranslateY: function () {\n\n\t\tvar v1 = new Vector3( 0, 1, 0 );\n\n\t\treturn function translateY( distance ) {\n\n\t\t\treturn this.translateOnAxis( v1, distance );\n\n\t\t};\n\n\t}(),\n\n\ttranslateZ: function () {\n\n\t\tvar v1 = new Vector3( 0, 0, 1 );\n\n\t\treturn function translateZ( distance ) {\n\n\t\t\treturn this.translateOnAxis( v1, distance );\n\n\t\t};\n\n\t}(),\n\n\tlocalToWorld: function ( vector ) {\n\n\t\treturn vector.applyMatrix4( this.matrixWorld );\n\n\t},\n\n\tworldToLocal: function () {\n\n\t\tvar m1 = new Matrix4();\n\n\t\treturn function worldToLocal( vector ) {\n\n\t\t\treturn vector.applyMatrix4( m1.getInverse( this.matrixWorld ) );\n\n\t\t};\n\n\t}(),\n\n\tlookAt: function () {\n\n\t\t// This routine does not support objects with rotated and/or translated parent(s)\n\n\t\tvar m1 = new Matrix4();\n\n\t\treturn function lookAt( vector ) {\n\n\t\t\tm1.lookAt( vector, this.position, this.up );\n\n\t\t\tthis.quaternion.setFromRotationMatrix( m1 );\n\n\t\t};\n\n\t}(),\n\n\tadd: function ( object ) {\n\n\t\tif ( arguments.length > 1 ) {\n\n\t\t\tfor ( var i = 0; i < arguments.length; i ++ ) {\n\n\t\t\t\tthis.add( arguments[ i ] );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tif ( object === this ) {\n\n\t\t\tconsole.error( \"THREE.Object3D.add: object can't be added as a child of itself.\", object );\n\t\t\treturn this;\n\n\t\t}\n\n\t\tif ( ( object && object.isObject3D ) ) {\n\n\t\t\tif ( object.parent !== null ) {\n\n\t\t\t\tobject.parent.remove( object );\n\n\t\t\t}\n\n\t\t\tobject.parent = this;\n\t\t\tobject.dispatchEvent( { type: 'added' } );\n\n\t\t\tthis.children.push( object );\n\n\t\t} else {\n\n\t\t\tconsole.error( \"THREE.Object3D.add: object not an instance of THREE.Object3D.\", object );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tremove: function ( object ) {\n\n\t\tif ( arguments.length > 1 ) {\n\n\t\t\tfor ( var i = 0; i < arguments.length; i ++ ) {\n\n\t\t\t\tthis.remove( arguments[ i ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar index = this.children.indexOf( object );\n\n\t\tif ( index !== - 1 ) {\n\n\t\t\tobject.parent = null;\n\n\t\t\tobject.dispatchEvent( { type: 'removed' } );\n\n\t\t\tthis.children.splice( index, 1 );\n\n\t\t}\n\n\t},\n\n\tgetObjectById: function ( id ) {\n\n\t\treturn this.getObjectByProperty( 'id', id );\n\n\t},\n\n\tgetObjectByName: function ( name ) {\n\n\t\treturn this.getObjectByProperty( 'name', name );\n\n\t},\n\n\tgetObjectByProperty: function ( name, value ) {\n\n\t\tif ( this[ name ] === value ) return this;\n\n\t\tfor ( var i = 0, l = this.children.length; i < l; i ++ ) {\n\n\t\t\tvar child = this.children[ i ];\n\t\t\tvar object = child.getObjectByProperty( name, value );\n\n\t\t\tif ( object !== undefined ) {\n\n\t\t\t\treturn object;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn undefined;\n\n\t},\n\n\tgetWorldPosition: function ( optionalTarget ) {\n\n\t\tvar result = optionalTarget || new Vector3();\n\n\t\tthis.updateMatrixWorld( true );\n\n\t\treturn result.setFromMatrixPosition( this.matrixWorld );\n\n\t},\n\n\tgetWorldQuaternion: function () {\n\n\t\tvar position = new Vector3();\n\t\tvar scale = new Vector3();\n\n\t\treturn function getWorldQuaternion( optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Quaternion();\n\n\t\t\tthis.updateMatrixWorld( true );\n\n\t\t\tthis.matrixWorld.decompose( position, result, scale );\n\n\t\t\treturn result;\n\n\t\t};\n\n\t}(),\n\n\tgetWorldRotation: function () {\n\n\t\tvar quaternion = new Quaternion();\n\n\t\treturn function getWorldRotation( optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Euler();\n\n\t\t\tthis.getWorldQuaternion( quaternion );\n\n\t\t\treturn result.setFromQuaternion( quaternion, this.rotation.order, false );\n\n\t\t};\n\n\t}(),\n\n\tgetWorldScale: function () {\n\n\t\tvar position = new Vector3();\n\t\tvar quaternion = new Quaternion();\n\n\t\treturn function getWorldScale( optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\n\t\t\tthis.updateMatrixWorld( true );\n\n\t\t\tthis.matrixWorld.decompose( position, quaternion, result );\n\n\t\t\treturn result;\n\n\t\t};\n\n\t}(),\n\n\tgetWorldDirection: function () {\n\n\t\tvar quaternion = new Quaternion();\n\n\t\treturn function getWorldDirection( optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\n\t\t\tthis.getWorldQuaternion( quaternion );\n\n\t\t\treturn result.set( 0, 0, 1 ).applyQuaternion( quaternion );\n\n\t\t};\n\n\t}(),\n\n\traycast: function () {},\n\n\ttraverse: function ( callback ) {\n\n\t\tcallback( this );\n\n\t\tvar children = this.children;\n\n\t\tfor ( var i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tchildren[ i ].traverse( callback );\n\n\t\t}\n\n\t},\n\n\ttraverseVisible: function ( callback ) {\n\n\t\tif ( this.visible === false ) return;\n\n\t\tcallback( this );\n\n\t\tvar children = this.children;\n\n\t\tfor ( var i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tchildren[ i ].traverseVisible( callback );\n\n\t\t}\n\n\t},\n\n\ttraverseAncestors: function ( callback ) {\n\n\t\tvar parent = this.parent;\n\n\t\tif ( parent !== null ) {\n\n\t\t\tcallback( parent );\n\n\t\t\tparent.traverseAncestors( callback );\n\n\t\t}\n\n\t},\n\n\tupdateMatrix: function () {\n\n\t\tthis.matrix.compose( this.position, this.quaternion, this.scale );\n\n\t\tthis.matrixWorldNeedsUpdate = true;\n\n\t},\n\n\tupdateMatrixWorld: function ( force ) {\n\n\t\tif ( this.matrixAutoUpdate === true ) this.updateMatrix();\n\n\t\tif ( this.matrixWorldNeedsUpdate === true || force === true ) {\n\n\t\t\tif ( this.parent === null ) {\n\n\t\t\t\tthis.matrixWorld.copy( this.matrix );\n\n\t\t\t} else {\n\n\t\t\t\tthis.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );\n\n\t\t\t}\n\n\t\t\tthis.matrixWorldNeedsUpdate = false;\n\n\t\t\tforce = true;\n\n\t\t}\n\n\t\t// update children\n\n\t\tvar children = this.children;\n\n\t\tfor ( var i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tchildren[ i ].updateMatrixWorld( force );\n\n\t\t}\n\n\t},\n\n\ttoJSON: function ( meta ) {\n\n\t\t// meta is '' when called from JSON.stringify\n\t\tvar isRootObject = ( meta === undefined || meta === '' );\n\n\t\tvar output = {};\n\n\t\t// meta is a hash used to collect geometries, materials.\n\t\t// not providing it implies that this is the root object\n\t\t// being serialized.\n\t\tif ( isRootObject ) {\n\n\t\t\t// initialize meta obj\n\t\t\tmeta = {\n\t\t\t\tgeometries: {},\n\t\t\t\tmaterials: {},\n\t\t\t\ttextures: {},\n\t\t\t\timages: {}\n\t\t\t};\n\n\t\t\toutput.metadata = {\n\t\t\t\tversion: 4.4,\n\t\t\t\ttype: 'Object',\n\t\t\t\tgenerator: 'Object3D.toJSON'\n\t\t\t};\n\n\t\t}\n\n\t\t// standard Object3D serialization\n\n\t\tvar object = {};\n\n\t\tobject.uuid = this.uuid;\n\t\tobject.type = this.type;\n\n\t\tif ( this.name !== '' ) object.name = this.name;\n\t\tif ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData;\n\t\tif ( this.castShadow === true ) object.castShadow = true;\n\t\tif ( this.receiveShadow === true ) object.receiveShadow = true;\n\t\tif ( this.visible === false ) object.visible = false;\n\n\t\tobject.matrix = this.matrix.toArray();\n\n\t\t//\n\n\t\tif ( this.geometry !== undefined ) {\n\n\t\t\tif ( meta.geometries[ this.geometry.uuid ] === undefined ) {\n\n\t\t\t\tmeta.geometries[ this.geometry.uuid ] = this.geometry.toJSON( meta );\n\n\t\t\t}\n\n\t\t\tobject.geometry = this.geometry.uuid;\n\n\t\t}\n\n\t\tif ( this.material !== undefined ) {\n\n\t\t\tif ( meta.materials[ this.material.uuid ] === undefined ) {\n\n\t\t\t\tmeta.materials[ this.material.uuid ] = this.material.toJSON( meta );\n\n\t\t\t}\n\n\t\t\tobject.material = this.material.uuid;\n\n\t\t}\n\n\t\t//\n\n\t\tif ( this.children.length > 0 ) {\n\n\t\t\tobject.children = [];\n\n\t\t\tfor ( var i = 0; i < this.children.length; i ++ ) {\n\n\t\t\t\tobject.children.push( this.children[ i ].toJSON( meta ).object );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( isRootObject ) {\n\n\t\t\tvar geometries = extractFromCache( meta.geometries );\n\t\t\tvar materials = extractFromCache( meta.materials );\n\t\t\tvar textures = extractFromCache( meta.textures );\n\t\t\tvar images = extractFromCache( meta.images );\n\n\t\t\tif ( geometries.length > 0 ) output.geometries = geometries;\n\t\t\tif ( materials.length > 0 ) output.materials = materials;\n\t\t\tif ( textures.length > 0 ) output.textures = textures;\n\t\t\tif ( images.length > 0 ) output.images = images;\n\n\t\t}\n\n\t\toutput.object = object;\n\n\t\treturn output;\n\n\t\t// extract data from the cache hash\n\t\t// remove metadata on each item\n\t\t// and return as array\n\t\tfunction extractFromCache( cache ) {\n\n\t\t\tvar values = [];\n\t\t\tfor ( var key in cache ) {\n\n\t\t\t\tvar data = cache[ key ];\n\t\t\t\tdelete data.metadata;\n\t\t\t\tvalues.push( data );\n\n\t\t\t}\n\t\t\treturn values;\n\n\t\t}\n\n\t},\n\n\tclone: function ( recursive ) {\n\n\t\treturn new this.constructor().copy( this, recursive );\n\n\t},\n\n\tcopy: function ( source, recursive ) {\n\n\t\tif ( recursive === undefined ) recursive = true;\n\n\t\tthis.name = source.name;\n\n\t\tthis.up.copy( source.up );\n\n\t\tthis.position.copy( source.position );\n\t\tthis.quaternion.copy( source.quaternion );\n\t\tthis.scale.copy( source.scale );\n\n\t\tthis.matrix.copy( source.matrix );\n\t\tthis.matrixWorld.copy( source.matrixWorld );\n\n\t\tthis.matrixAutoUpdate = source.matrixAutoUpdate;\n\t\tthis.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;\n\n\t\tthis.layers.mask = source.layers.mask;\n\t\tthis.visible = source.visible;\n\n\t\tthis.castShadow = source.castShadow;\n\t\tthis.receiveShadow = source.receiveShadow;\n\n\t\tthis.frustumCulled = source.frustumCulled;\n\t\tthis.renderOrder = source.renderOrder;\n\n\t\tthis.userData = JSON.parse( JSON.stringify( source.userData ) );\n\n\t\tif ( recursive === true ) {\n\n\t\t\tfor ( var i = 0; i < source.children.length; i ++ ) {\n\n\t\t\t\tvar child = source.children[ i ];\n\t\t\t\tthis.add( child.clone() );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n};\n\nObject.assign( Object3D.prototype, EventDispatcher.prototype );\n\n/**\n * @author bhouston / http://clara.io\n */\n\nfunction Line3( start, end ) {\n\n\tthis.start = ( start !== undefined ) ? start : new Vector3();\n\tthis.end = ( end !== undefined ) ? end : new Vector3();\n\n}\n\nLine3.prototype = {\n\n\tconstructor: Line3,\n\n\tset: function ( start, end ) {\n\n\t\tthis.start.copy( start );\n\t\tthis.end.copy( end );\n\n\t\treturn this;\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor().copy( this );\n\n\t},\n\n\tcopy: function ( line ) {\n\n\t\tthis.start.copy( line.start );\n\t\tthis.end.copy( line.end );\n\n\t\treturn this;\n\n\t},\n\n\tgetCenter: function ( optionalTarget ) {\n\n\t\tvar result = optionalTarget || new Vector3();\n\t\treturn result.addVectors( this.start, this.end ).multiplyScalar( 0.5 );\n\n\t},\n\n\tdelta: function ( optionalTarget ) {\n\n\t\tvar result = optionalTarget || new Vector3();\n\t\treturn result.subVectors( this.end, this.start );\n\n\t},\n\n\tdistanceSq: function () {\n\n\t\treturn this.start.distanceToSquared( this.end );\n\n\t},\n\n\tdistance: function () {\n\n\t\treturn this.start.distanceTo( this.end );\n\n\t},\n\n\tat: function ( t, optionalTarget ) {\n\n\t\tvar result = optionalTarget || new Vector3();\n\n\t\treturn this.delta( result ).multiplyScalar( t ).add( this.start );\n\n\t},\n\n\tclosestPointToPointParameter: function () {\n\n\t\tvar startP = new Vector3();\n\t\tvar startEnd = new Vector3();\n\n\t\treturn function closestPointToPointParameter( point, clampToLine ) {\n\n\t\t\tstartP.subVectors( point, this.start );\n\t\t\tstartEnd.subVectors( this.end, this.start );\n\n\t\t\tvar startEnd2 = startEnd.dot( startEnd );\n\t\t\tvar startEnd_startP = startEnd.dot( startP );\n\n\t\t\tvar t = startEnd_startP / startEnd2;\n\n\t\t\tif ( clampToLine ) {\n\n\t\t\t\tt = _Math.clamp( t, 0, 1 );\n\n\t\t\t}\n\n\t\t\treturn t;\n\n\t\t};\n\n\t}(),\n\n\tclosestPointToPoint: function ( point, clampToLine, optionalTarget ) {\n\n\t\tvar t = this.closestPointToPointParameter( point, clampToLine );\n\n\t\tvar result = optionalTarget || new Vector3();\n\n\t\treturn this.delta( result ).multiplyScalar( t ).add( this.start );\n\n\t},\n\n\tapplyMatrix4: function ( matrix ) {\n\n\t\tthis.start.applyMatrix4( matrix );\n\t\tthis.end.applyMatrix4( matrix );\n\n\t\treturn this;\n\n\t},\n\n\tequals: function ( line ) {\n\n\t\treturn line.start.equals( this.start ) && line.end.equals( this.end );\n\n\t}\n\n};\n\n/**\n * @author bhouston / http://clara.io\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction Triangle( a, b, c ) {\n\n\tthis.a = ( a !== undefined ) ? a : new Vector3();\n\tthis.b = ( b !== undefined ) ? b : new Vector3();\n\tthis.c = ( c !== undefined ) ? c : new Vector3();\n\n}\n\nTriangle.normal = function () {\n\n\tvar v0 = new Vector3();\n\n\treturn function normal( a, b, c, optionalTarget ) {\n\n\t\tvar result = optionalTarget || new Vector3();\n\n\t\tresult.subVectors( c, b );\n\t\tv0.subVectors( a, b );\n\t\tresult.cross( v0 );\n\n\t\tvar resultLengthSq = result.lengthSq();\n\t\tif ( resultLengthSq > 0 ) {\n\n\t\t\treturn result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) );\n\n\t\t}\n\n\t\treturn result.set( 0, 0, 0 );\n\n\t};\n\n}();\n\n// static/instance method to calculate barycentric coordinates\n// based on: http://www.blackpawn.com/texts/pointinpoly/default.html\nTriangle.barycoordFromPoint = function () {\n\n\tvar v0 = new Vector3();\n\tvar v1 = new Vector3();\n\tvar v2 = new Vector3();\n\n\treturn function barycoordFromPoint( point, a, b, c, optionalTarget ) {\n\n\t\tv0.subVectors( c, a );\n\t\tv1.subVectors( b, a );\n\t\tv2.subVectors( point, a );\n\n\t\tvar dot00 = v0.dot( v0 );\n\t\tvar dot01 = v0.dot( v1 );\n\t\tvar dot02 = v0.dot( v2 );\n\t\tvar dot11 = v1.dot( v1 );\n\t\tvar dot12 = v1.dot( v2 );\n\n\t\tvar denom = ( dot00 * dot11 - dot01 * dot01 );\n\n\t\tvar result = optionalTarget || new Vector3();\n\n\t\t// collinear or singular triangle\n\t\tif ( denom === 0 ) {\n\n\t\t\t// arbitrary location outside of triangle?\n\t\t\t// not sure if this is the best idea, maybe should be returning undefined\n\t\t\treturn result.set( - 2, - 1, - 1 );\n\n\t\t}\n\n\t\tvar invDenom = 1 / denom;\n\t\tvar u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;\n\t\tvar v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;\n\n\t\t// barycentric coordinates must always sum to 1\n\t\treturn result.set( 1 - u - v, v, u );\n\n\t};\n\n}();\n\nTriangle.containsPoint = function () {\n\n\tvar v1 = new Vector3();\n\n\treturn function containsPoint( point, a, b, c ) {\n\n\t\tvar result = Triangle.barycoordFromPoint( point, a, b, c, v1 );\n\n\t\treturn ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 );\n\n\t};\n\n}();\n\nTriangle.prototype = {\n\n\tconstructor: Triangle,\n\n\tset: function ( a, b, c ) {\n\n\t\tthis.a.copy( a );\n\t\tthis.b.copy( b );\n\t\tthis.c.copy( c );\n\n\t\treturn this;\n\n\t},\n\n\tsetFromPointsAndIndices: function ( points, i0, i1, i2 ) {\n\n\t\tthis.a.copy( points[ i0 ] );\n\t\tthis.b.copy( points[ i1 ] );\n\t\tthis.c.copy( points[ i2 ] );\n\n\t\treturn this;\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor().copy( this );\n\n\t},\n\n\tcopy: function ( triangle ) {\n\n\t\tthis.a.copy( triangle.a );\n\t\tthis.b.copy( triangle.b );\n\t\tthis.c.copy( triangle.c );\n\n\t\treturn this;\n\n\t},\n\n\tarea: function () {\n\n\t\tvar v0 = new Vector3();\n\t\tvar v1 = new Vector3();\n\n\t\treturn function area() {\n\n\t\t\tv0.subVectors( this.c, this.b );\n\t\t\tv1.subVectors( this.a, this.b );\n\n\t\t\treturn v0.cross( v1 ).length() * 0.5;\n\n\t\t};\n\n\t}(),\n\n\tmidpoint: function ( optionalTarget ) {\n\n\t\tvar result = optionalTarget || new Vector3();\n\t\treturn result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );\n\n\t},\n\n\tnormal: function ( optionalTarget ) {\n\n\t\treturn Triangle.normal( this.a, this.b, this.c, optionalTarget );\n\n\t},\n\n\tplane: function ( optionalTarget ) {\n\n\t\tvar result = optionalTarget || new Plane();\n\n\t\treturn result.setFromCoplanarPoints( this.a, this.b, this.c );\n\n\t},\n\n\tbarycoordFromPoint: function ( point, optionalTarget ) {\n\n\t\treturn Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget );\n\n\t},\n\n\tcontainsPoint: function ( point ) {\n\n\t\treturn Triangle.containsPoint( point, this.a, this.b, this.c );\n\n\t},\n\n\tclosestPointToPoint: function () {\n\n\t\tvar plane, edgeList, projectedPoint, closestPoint;\n\n\t\treturn function closestPointToPoint( point, optionalTarget ) {\n\n\t\t\tif ( plane === undefined ) {\n\n\t\t\t\tplane = new Plane();\n\t\t\t\tedgeList = [ new Line3(), new Line3(), new Line3() ];\n\t\t\t\tprojectedPoint = new Vector3();\n\t\t\t\tclosestPoint = new Vector3();\n\n\t\t\t}\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\t\t\tvar minDistance = Infinity;\n\n\t\t\t// project the point onto the plane of the triangle\n\n\t\t\tplane.setFromCoplanarPoints( this.a, this.b, this.c );\n\t\t\tplane.projectPoint( point, projectedPoint );\n\n\t\t\t// check if the projection lies within the triangle\n\n\t\t\tif( this.containsPoint( projectedPoint ) === true ) {\n\n\t\t\t\t// if so, this is the closest point\n\n\t\t\t\tresult.copy( projectedPoint );\n\n\t\t\t} else {\n\n\t\t\t\t// if not, the point falls outside the triangle. the result is the closest point to the triangle's edges or vertices\n\n\t\t\t\tedgeList[ 0 ].set( this.a, this.b );\n\t\t\t\tedgeList[ 1 ].set( this.b, this.c );\n\t\t\t\tedgeList[ 2 ].set( this.c, this.a );\n\n\t\t\t\tfor( var i = 0; i < edgeList.length; i ++ ) {\n\n\t\t\t\t\tedgeList[ i ].closestPointToPoint( projectedPoint, true, closestPoint );\n\n\t\t\t\t\tvar distance = projectedPoint.distanceToSquared( closestPoint );\n\n\t\t\t\t\tif( distance < minDistance ) {\n\n\t\t\t\t\t\tminDistance = distance;\n\n\t\t\t\t\t\tresult.copy( closestPoint );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn result;\n\n\t\t};\n\n\t}(),\n\n\tequals: function ( triangle ) {\n\n\t\treturn triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );\n\n\t}\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction Face3( a, b, c, normal, color, materialIndex ) {\n\n\tthis.a = a;\n\tthis.b = b;\n\tthis.c = c;\n\n\tthis.normal = (normal && normal.isVector3) ? normal : new Vector3();\n\tthis.vertexNormals = Array.isArray( normal ) ? normal : [];\n\n\tthis.color = (color && color.isColor) ? color : new Color();\n\tthis.vertexColors = Array.isArray( color ) ? color : [];\n\n\tthis.materialIndex = materialIndex !== undefined ? materialIndex : 0;\n\n}\n\nFace3.prototype = {\n\n\tconstructor: Face3,\n\n\tclone: function () {\n\n\t\treturn new this.constructor().copy( this );\n\n\t},\n\n\tcopy: function ( source ) {\n\n\t\tthis.a = source.a;\n\t\tthis.b = source.b;\n\t\tthis.c = source.c;\n\n\t\tthis.normal.copy( source.normal );\n\t\tthis.color.copy( source.color );\n\n\t\tthis.materialIndex = source.materialIndex;\n\n\t\tfor ( var i = 0, il = source.vertexNormals.length; i < il; i ++ ) {\n\n\t\t\tthis.vertexNormals[ i ] = source.vertexNormals[ i ].clone();\n\n\t\t}\n\n\t\tfor ( var i = 0, il = source.vertexColors.length; i < il; i ++ ) {\n\n\t\t\tthis.vertexColors[ i ] = source.vertexColors[ i ].clone();\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author alteredq / http://alteredqualia.com/\n *\n * parameters = {\n * color: ,\n * opacity: ,\n * map: new THREE.Texture( ),\n *\n * lightMap: new THREE.Texture( ),\n * lightMapIntensity: \n *\n * aoMap: new THREE.Texture( ),\n * aoMapIntensity: \n *\n * specularMap: new THREE.Texture( ),\n *\n * alphaMap: new THREE.Texture( ),\n *\n * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),\n * combine: THREE.Multiply,\n * reflectivity: ,\n * refractionRatio: ,\n *\n * shading: THREE.SmoothShading,\n * depthTest: ,\n * depthWrite: ,\n *\n * wireframe: ,\n * wireframeLinewidth: ,\n *\n * skinning: ,\n * morphTargets: \n * }\n */\n\nfunction MeshBasicMaterial( parameters ) {\n\n\tMaterial.call( this );\n\n\tthis.type = 'MeshBasicMaterial';\n\n\tthis.color = new Color( 0xffffff ); // emissive\n\n\tthis.map = null;\n\n\tthis.lightMap = null;\n\tthis.lightMapIntensity = 1.0;\n\n\tthis.aoMap = null;\n\tthis.aoMapIntensity = 1.0;\n\n\tthis.specularMap = null;\n\n\tthis.alphaMap = null;\n\n\tthis.envMap = null;\n\tthis.combine = MultiplyOperation;\n\tthis.reflectivity = 1;\n\tthis.refractionRatio = 0.98;\n\n\tthis.wireframe = false;\n\tthis.wireframeLinewidth = 1;\n\tthis.wireframeLinecap = 'round';\n\tthis.wireframeLinejoin = 'round';\n\n\tthis.skinning = false;\n\tthis.morphTargets = false;\n\n\tthis.lights = false;\n\n\tthis.setValues( parameters );\n\n}\n\nMeshBasicMaterial.prototype = Object.create( Material.prototype );\nMeshBasicMaterial.prototype.constructor = MeshBasicMaterial;\n\nMeshBasicMaterial.prototype.isMeshBasicMaterial = true;\n\nMeshBasicMaterial.prototype.copy = function ( source ) {\n\n\tMaterial.prototype.copy.call( this, source );\n\n\tthis.color.copy( source.color );\n\n\tthis.map = source.map;\n\n\tthis.lightMap = source.lightMap;\n\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\tthis.aoMap = source.aoMap;\n\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\tthis.specularMap = source.specularMap;\n\n\tthis.alphaMap = source.alphaMap;\n\n\tthis.envMap = source.envMap;\n\tthis.combine = source.combine;\n\tthis.reflectivity = source.reflectivity;\n\tthis.refractionRatio = source.refractionRatio;\n\n\tthis.wireframe = source.wireframe;\n\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\tthis.wireframeLinecap = source.wireframeLinecap;\n\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\tthis.skinning = source.skinning;\n\tthis.morphTargets = source.morphTargets;\n\n\treturn this;\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction BufferAttribute( array, itemSize, normalized ) {\n\n\tif ( Array.isArray( array ) ) {\n\n\t\tthrow new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );\n\n\t}\n\n\tthis.uuid = _Math.generateUUID();\n\n\tthis.array = array;\n\tthis.itemSize = itemSize;\n\tthis.count = array !== undefined ? array.length / itemSize : 0;\n\tthis.normalized = normalized === true;\n\n\tthis.dynamic = false;\n\tthis.updateRange = { offset: 0, count: - 1 };\n\n\tthis.onUploadCallback = function () {};\n\n\tthis.version = 0;\n\n}\n\nBufferAttribute.prototype = {\n\n\tconstructor: BufferAttribute,\n\n\tisBufferAttribute: true,\n\n\tset needsUpdate( value ) {\n\n\t\tif ( value === true ) this.version ++;\n\n\t},\n\n\tsetArray: function ( array ) {\n\n\t\tif ( Array.isArray( array ) ) {\n\n\t\t\tthrow new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );\n\n\t\t}\n\n\t\tthis.count = array !== undefined ? array.length / this.itemSize : 0;\n\t\tthis.array = array;\n\n\t},\n\n\tsetDynamic: function ( value ) {\n\n\t\tthis.dynamic = value;\n\n\t\treturn this;\n\n\t},\n\n\tcopy: function ( source ) {\n\n\t\tthis.array = new source.array.constructor( source.array );\n\t\tthis.itemSize = source.itemSize;\n\t\tthis.count = source.count;\n\t\tthis.normalized = source.normalized;\n\n\t\tthis.dynamic = source.dynamic;\n\n\t\treturn this;\n\n\t},\n\n\tcopyAt: function ( index1, attribute, index2 ) {\n\n\t\tindex1 *= this.itemSize;\n\t\tindex2 *= attribute.itemSize;\n\n\t\tfor ( var i = 0, l = this.itemSize; i < l; i ++ ) {\n\n\t\t\tthis.array[ index1 + i ] = attribute.array[ index2 + i ];\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tcopyArray: function ( array ) {\n\n\t\tthis.array.set( array );\n\n\t\treturn this;\n\n\t},\n\n\tcopyColorsArray: function ( colors ) {\n\n\t\tvar array = this.array, offset = 0;\n\n\t\tfor ( var i = 0, l = colors.length; i < l; i ++ ) {\n\n\t\t\tvar color = colors[ i ];\n\n\t\t\tif ( color === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i );\n\t\t\t\tcolor = new Color();\n\n\t\t\t}\n\n\t\t\tarray[ offset ++ ] = color.r;\n\t\t\tarray[ offset ++ ] = color.g;\n\t\t\tarray[ offset ++ ] = color.b;\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tcopyIndicesArray: function ( indices ) {\n\n\t\tvar array = this.array, offset = 0;\n\n\t\tfor ( var i = 0, l = indices.length; i < l; i ++ ) {\n\n\t\t\tvar index = indices[ i ];\n\n\t\t\tarray[ offset ++ ] = index.a;\n\t\t\tarray[ offset ++ ] = index.b;\n\t\t\tarray[ offset ++ ] = index.c;\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tcopyVector2sArray: function ( vectors ) {\n\n\t\tvar array = this.array, offset = 0;\n\n\t\tfor ( var i = 0, l = vectors.length; i < l; i ++ ) {\n\n\t\t\tvar vector = vectors[ i ];\n\n\t\t\tif ( vector === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i );\n\t\t\t\tvector = new Vector2();\n\n\t\t\t}\n\n\t\t\tarray[ offset ++ ] = vector.x;\n\t\t\tarray[ offset ++ ] = vector.y;\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tcopyVector3sArray: function ( vectors ) {\n\n\t\tvar array = this.array, offset = 0;\n\n\t\tfor ( var i = 0, l = vectors.length; i < l; i ++ ) {\n\n\t\t\tvar vector = vectors[ i ];\n\n\t\t\tif ( vector === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i );\n\t\t\t\tvector = new Vector3();\n\n\t\t\t}\n\n\t\t\tarray[ offset ++ ] = vector.x;\n\t\t\tarray[ offset ++ ] = vector.y;\n\t\t\tarray[ offset ++ ] = vector.z;\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tcopyVector4sArray: function ( vectors ) {\n\n\t\tvar array = this.array, offset = 0;\n\n\t\tfor ( var i = 0, l = vectors.length; i < l; i ++ ) {\n\n\t\t\tvar vector = vectors[ i ];\n\n\t\t\tif ( vector === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i );\n\t\t\t\tvector = new Vector4();\n\n\t\t\t}\n\n\t\t\tarray[ offset ++ ] = vector.x;\n\t\t\tarray[ offset ++ ] = vector.y;\n\t\t\tarray[ offset ++ ] = vector.z;\n\t\t\tarray[ offset ++ ] = vector.w;\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tset: function ( value, offset ) {\n\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tthis.array.set( value, offset );\n\n\t\treturn this;\n\n\t},\n\n\tgetX: function ( index ) {\n\n\t\treturn this.array[ index * this.itemSize ];\n\n\t},\n\n\tsetX: function ( index, x ) {\n\n\t\tthis.array[ index * this.itemSize ] = x;\n\n\t\treturn this;\n\n\t},\n\n\tgetY: function ( index ) {\n\n\t\treturn this.array[ index * this.itemSize + 1 ];\n\n\t},\n\n\tsetY: function ( index, y ) {\n\n\t\tthis.array[ index * this.itemSize + 1 ] = y;\n\n\t\treturn this;\n\n\t},\n\n\tgetZ: function ( index ) {\n\n\t\treturn this.array[ index * this.itemSize + 2 ];\n\n\t},\n\n\tsetZ: function ( index, z ) {\n\n\t\tthis.array[ index * this.itemSize + 2 ] = z;\n\n\t\treturn this;\n\n\t},\n\n\tgetW: function ( index ) {\n\n\t\treturn this.array[ index * this.itemSize + 3 ];\n\n\t},\n\n\tsetW: function ( index, w ) {\n\n\t\tthis.array[ index * this.itemSize + 3 ] = w;\n\n\t\treturn this;\n\n\t},\n\n\tsetXY: function ( index, x, y ) {\n\n\t\tindex *= this.itemSize;\n\n\t\tthis.array[ index + 0 ] = x;\n\t\tthis.array[ index + 1 ] = y;\n\n\t\treturn this;\n\n\t},\n\n\tsetXYZ: function ( index, x, y, z ) {\n\n\t\tindex *= this.itemSize;\n\n\t\tthis.array[ index + 0 ] = x;\n\t\tthis.array[ index + 1 ] = y;\n\t\tthis.array[ index + 2 ] = z;\n\n\t\treturn this;\n\n\t},\n\n\tsetXYZW: function ( index, x, y, z, w ) {\n\n\t\tindex *= this.itemSize;\n\n\t\tthis.array[ index + 0 ] = x;\n\t\tthis.array[ index + 1 ] = y;\n\t\tthis.array[ index + 2 ] = z;\n\t\tthis.array[ index + 3 ] = w;\n\n\t\treturn this;\n\n\t},\n\n\tonUpload: function ( callback ) {\n\n\t\tthis.onUploadCallback = callback;\n\n\t\treturn this;\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor( this.array, this.itemSize ).copy( this );\n\n\t}\n\n};\n\n//\n\nfunction Int8BufferAttribute( array, itemSize ) {\n\n\tBufferAttribute.call( this, new Int8Array( array ), itemSize );\n\n}\n\nInt8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );\nInt8BufferAttribute.prototype.constructor = Int8BufferAttribute;\n\n\nfunction Uint8BufferAttribute( array, itemSize ) {\n\n\tBufferAttribute.call( this, new Uint8Array( array ), itemSize );\n\n}\n\nUint8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );\nUint8BufferAttribute.prototype.constructor = Uint8BufferAttribute;\n\n\nfunction Uint8ClampedBufferAttribute( array, itemSize ) {\n\n\tBufferAttribute.call( this, new Uint8ClampedArray( array ), itemSize );\n\n}\n\nUint8ClampedBufferAttribute.prototype = Object.create( BufferAttribute.prototype );\nUint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute;\n\n\nfunction Int16BufferAttribute( array, itemSize ) {\n\n\tBufferAttribute.call( this, new Int16Array( array ), itemSize );\n\n}\n\nInt16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );\nInt16BufferAttribute.prototype.constructor = Int16BufferAttribute;\n\n\nfunction Uint16BufferAttribute( array, itemSize ) {\n\n\tBufferAttribute.call( this, new Uint16Array( array ), itemSize );\n\n}\n\nUint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );\nUint16BufferAttribute.prototype.constructor = Uint16BufferAttribute;\n\n\nfunction Int32BufferAttribute( array, itemSize ) {\n\n\tBufferAttribute.call( this, new Int32Array( array ), itemSize );\n\n}\n\nInt32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );\nInt32BufferAttribute.prototype.constructor = Int32BufferAttribute;\n\n\nfunction Uint32BufferAttribute( array, itemSize ) {\n\n\tBufferAttribute.call( this, new Uint32Array( array ), itemSize );\n\n}\n\nUint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );\nUint32BufferAttribute.prototype.constructor = Uint32BufferAttribute;\n\n\nfunction Float32BufferAttribute( array, itemSize ) {\n\n\tBufferAttribute.call( this, new Float32Array( array ), itemSize );\n\n}\n\nFloat32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );\nFloat32BufferAttribute.prototype.constructor = Float32BufferAttribute;\n\n\nfunction Float64BufferAttribute( array, itemSize ) {\n\n\tBufferAttribute.call( this, new Float64Array( array ), itemSize );\n\n}\n\nFloat64BufferAttribute.prototype = Object.create( BufferAttribute.prototype );\nFloat64BufferAttribute.prototype.constructor = Float64BufferAttribute;\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction DirectGeometry() {\n\n\tthis.indices = [];\n\tthis.vertices = [];\n\tthis.normals = [];\n\tthis.colors = [];\n\tthis.uvs = [];\n\tthis.uvs2 = [];\n\n\tthis.groups = [];\n\n\tthis.morphTargets = {};\n\n\tthis.skinWeights = [];\n\tthis.skinIndices = [];\n\n\t// this.lineDistances = [];\n\n\tthis.boundingBox = null;\n\tthis.boundingSphere = null;\n\n\t// update flags\n\n\tthis.verticesNeedUpdate = false;\n\tthis.normalsNeedUpdate = false;\n\tthis.colorsNeedUpdate = false;\n\tthis.uvsNeedUpdate = false;\n\tthis.groupsNeedUpdate = false;\n\n}\n\nObject.assign( DirectGeometry.prototype, {\n\n\tcomputeGroups: function ( geometry ) {\n\n\t\tvar group;\n\t\tvar groups = [];\n\t\tvar materialIndex = undefined;\n\n\t\tvar faces = geometry.faces;\n\n\t\tfor ( var i = 0; i < faces.length; i ++ ) {\n\n\t\t\tvar face = faces[ i ];\n\n\t\t\t// materials\n\n\t\t\tif ( face.materialIndex !== materialIndex ) {\n\n\t\t\t\tmaterialIndex = face.materialIndex;\n\n\t\t\t\tif ( group !== undefined ) {\n\n\t\t\t\t\tgroup.count = ( i * 3 ) - group.start;\n\t\t\t\t\tgroups.push( group );\n\n\t\t\t\t}\n\n\t\t\t\tgroup = {\n\t\t\t\t\tstart: i * 3,\n\t\t\t\t\tmaterialIndex: materialIndex\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( group !== undefined ) {\n\n\t\t\tgroup.count = ( i * 3 ) - group.start;\n\t\t\tgroups.push( group );\n\n\t\t}\n\n\t\tthis.groups = groups;\n\n\t},\n\n\tfromGeometry: function ( geometry ) {\n\n\t\tvar faces = geometry.faces;\n\t\tvar vertices = geometry.vertices;\n\t\tvar faceVertexUvs = geometry.faceVertexUvs;\n\n\t\tvar hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0;\n\t\tvar hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0;\n\n\t\t// morphs\n\n\t\tvar morphTargets = geometry.morphTargets;\n\t\tvar morphTargetsLength = morphTargets.length;\n\n\t\tvar morphTargetsPosition;\n\n\t\tif ( morphTargetsLength > 0 ) {\n\n\t\t\tmorphTargetsPosition = [];\n\n\t\t\tfor ( var i = 0; i < morphTargetsLength; i ++ ) {\n\n\t\t\t\tmorphTargetsPosition[ i ] = [];\n\n\t\t\t}\n\n\t\t\tthis.morphTargets.position = morphTargetsPosition;\n\n\t\t}\n\n\t\tvar morphNormals = geometry.morphNormals;\n\t\tvar morphNormalsLength = morphNormals.length;\n\n\t\tvar morphTargetsNormal;\n\n\t\tif ( morphNormalsLength > 0 ) {\n\n\t\t\tmorphTargetsNormal = [];\n\n\t\t\tfor ( var i = 0; i < morphNormalsLength; i ++ ) {\n\n\t\t\t\tmorphTargetsNormal[ i ] = [];\n\n\t\t\t}\n\n\t\t\tthis.morphTargets.normal = morphTargetsNormal;\n\n\t\t}\n\n\t\t// skins\n\n\t\tvar skinIndices = geometry.skinIndices;\n\t\tvar skinWeights = geometry.skinWeights;\n\n\t\tvar hasSkinIndices = skinIndices.length === vertices.length;\n\t\tvar hasSkinWeights = skinWeights.length === vertices.length;\n\n\t\t//\n\n\t\tfor ( var i = 0; i < faces.length; i ++ ) {\n\n\t\t\tvar face = faces[ i ];\n\n\t\t\tthis.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] );\n\n\t\t\tvar vertexNormals = face.vertexNormals;\n\n\t\t\tif ( vertexNormals.length === 3 ) {\n\n\t\t\t\tthis.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] );\n\n\t\t\t} else {\n\n\t\t\t\tvar normal = face.normal;\n\n\t\t\t\tthis.normals.push( normal, normal, normal );\n\n\t\t\t}\n\n\t\t\tvar vertexColors = face.vertexColors;\n\n\t\t\tif ( vertexColors.length === 3 ) {\n\n\t\t\t\tthis.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] );\n\n\t\t\t} else {\n\n\t\t\t\tvar color = face.color;\n\n\t\t\t\tthis.colors.push( color, color, color );\n\n\t\t\t}\n\n\t\t\tif ( hasFaceVertexUv === true ) {\n\n\t\t\t\tvar vertexUvs = faceVertexUvs[ 0 ][ i ];\n\n\t\t\t\tif ( vertexUvs !== undefined ) {\n\n\t\t\t\t\tthis.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i );\n\n\t\t\t\t\tthis.uvs.push( new Vector2(), new Vector2(), new Vector2() );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( hasFaceVertexUv2 === true ) {\n\n\t\t\t\tvar vertexUvs = faceVertexUvs[ 1 ][ i ];\n\n\t\t\t\tif ( vertexUvs !== undefined ) {\n\n\t\t\t\t\tthis.uvs2.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i );\n\n\t\t\t\t\tthis.uvs2.push( new Vector2(), new Vector2(), new Vector2() );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// morphs\n\n\t\t\tfor ( var j = 0; j < morphTargetsLength; j ++ ) {\n\n\t\t\t\tvar morphTarget = morphTargets[ j ].vertices;\n\n\t\t\t\tmorphTargetsPosition[ j ].push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] );\n\n\t\t\t}\n\n\t\t\tfor ( var j = 0; j < morphNormalsLength; j ++ ) {\n\n\t\t\t\tvar morphNormal = morphNormals[ j ].vertexNormals[ i ];\n\n\t\t\t\tmorphTargetsNormal[ j ].push( morphNormal.a, morphNormal.b, morphNormal.c );\n\n\t\t\t}\n\n\t\t\t// skins\n\n\t\t\tif ( hasSkinIndices ) {\n\n\t\t\t\tthis.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] );\n\n\t\t\t}\n\n\t\t\tif ( hasSkinWeights ) {\n\n\t\t\t\tthis.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.computeGroups( geometry );\n\n\t\tthis.verticesNeedUpdate = geometry.verticesNeedUpdate;\n\t\tthis.normalsNeedUpdate = geometry.normalsNeedUpdate;\n\t\tthis.colorsNeedUpdate = geometry.colorsNeedUpdate;\n\t\tthis.uvsNeedUpdate = geometry.uvsNeedUpdate;\n\t\tthis.groupsNeedUpdate = geometry.groupsNeedUpdate;\n\n\t\treturn this;\n\n\t}\n\n} );\n\n// http://stackoverflow.com/questions/1669190/javascript-min-max-array-values/13440842#13440842\n\nfunction arrayMax( array ) {\n\n\tvar length = array.length, max = - Infinity;\n\n\twhile ( length -- ) {\n\n\t\tif ( array[ length ] > max ) {\n\n\t\t\tmax = array[ length ];\n\n\t\t}\n\n\t}\n\n\treturn max;\n\n}\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author kile / http://kile.stravaganza.org/\n * @author alteredq / http://alteredqualia.com/\n * @author mikael emtinger / http://gomo.se/\n * @author zz85 / http://www.lab4games.net/zz85/blog\n * @author bhouston / http://clara.io\n */\n\nvar count = 0;\nfunction GeometryIdCount() { return count++; }\n\nfunction Geometry() {\n\n\tObject.defineProperty( this, 'id', { value: GeometryIdCount() } );\n\n\tthis.uuid = _Math.generateUUID();\n\n\tthis.name = '';\n\tthis.type = 'Geometry';\n\n\tthis.vertices = [];\n\tthis.colors = [];\n\tthis.faces = [];\n\tthis.faceVertexUvs = [[]];\n\n\tthis.morphTargets = [];\n\tthis.morphNormals = [];\n\n\tthis.skinWeights = [];\n\tthis.skinIndices = [];\n\n\tthis.lineDistances = [];\n\n\tthis.boundingBox = null;\n\tthis.boundingSphere = null;\n\n\t// update flags\n\n\tthis.elementsNeedUpdate = false;\n\tthis.verticesNeedUpdate = false;\n\tthis.uvsNeedUpdate = false;\n\tthis.normalsNeedUpdate = false;\n\tthis.colorsNeedUpdate = false;\n\tthis.lineDistancesNeedUpdate = false;\n\tthis.groupsNeedUpdate = false;\n\n}\n\nGeometry.prototype = {\n\n\tconstructor: Geometry,\n\n\tisGeometry: true,\n\n\tapplyMatrix: function ( matrix ) {\n\n\t\tvar normalMatrix = new Matrix3().getNormalMatrix( matrix );\n\n\t\tfor ( var i = 0, il = this.vertices.length; i < il; i ++ ) {\n\n\t\t\tvar vertex = this.vertices[ i ];\n\t\t\tvertex.applyMatrix4( matrix );\n\n\t\t}\n\n\t\tfor ( var i = 0, il = this.faces.length; i < il; i ++ ) {\n\n\t\t\tvar face = this.faces[ i ];\n\t\t\tface.normal.applyMatrix3( normalMatrix ).normalize();\n\n\t\t\tfor ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {\n\n\t\t\t\tface.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize();\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( this.boundingBox !== null ) {\n\n\t\t\tthis.computeBoundingBox();\n\n\t\t}\n\n\t\tif ( this.boundingSphere !== null ) {\n\n\t\t\tthis.computeBoundingSphere();\n\n\t\t}\n\n\t\tthis.verticesNeedUpdate = true;\n\t\tthis.normalsNeedUpdate = true;\n\n\t\treturn this;\n\n\t},\n\n\trotateX: function () {\n\n\t\t// rotate geometry around world x-axis\n\n\t\tvar m1;\n\n\t\treturn function rotateX( angle ) {\n\n\t\t\tif ( m1 === undefined ) m1 = new Matrix4();\n\n\t\t\tm1.makeRotationX( angle );\n\n\t\t\tthis.applyMatrix( m1 );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\trotateY: function () {\n\n\t\t// rotate geometry around world y-axis\n\n\t\tvar m1;\n\n\t\treturn function rotateY( angle ) {\n\n\t\t\tif ( m1 === undefined ) m1 = new Matrix4();\n\n\t\t\tm1.makeRotationY( angle );\n\n\t\t\tthis.applyMatrix( m1 );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\trotateZ: function () {\n\n\t\t// rotate geometry around world z-axis\n\n\t\tvar m1;\n\n\t\treturn function rotateZ( angle ) {\n\n\t\t\tif ( m1 === undefined ) m1 = new Matrix4();\n\n\t\t\tm1.makeRotationZ( angle );\n\n\t\t\tthis.applyMatrix( m1 );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\ttranslate: function () {\n\n\t\t// translate geometry\n\n\t\tvar m1;\n\n\t\treturn function translate( x, y, z ) {\n\n\t\t\tif ( m1 === undefined ) m1 = new Matrix4();\n\n\t\t\tm1.makeTranslation( x, y, z );\n\n\t\t\tthis.applyMatrix( m1 );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\tscale: function () {\n\n\t\t// scale geometry\n\n\t\tvar m1;\n\n\t\treturn function scale( x, y, z ) {\n\n\t\t\tif ( m1 === undefined ) m1 = new Matrix4();\n\n\t\t\tm1.makeScale( x, y, z );\n\n\t\t\tthis.applyMatrix( m1 );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\tlookAt: function () {\n\n\t\tvar obj;\n\n\t\treturn function lookAt( vector ) {\n\n\t\t\tif ( obj === undefined ) obj = new Object3D();\n\n\t\t\tobj.lookAt( vector );\n\n\t\t\tobj.updateMatrix();\n\n\t\t\tthis.applyMatrix( obj.matrix );\n\n\t\t};\n\n\t}(),\n\n\tfromBufferGeometry: function ( geometry ) {\n\n\t\tvar scope = this;\n\n\t\tvar indices = geometry.index !== null ? geometry.index.array : undefined;\n\t\tvar attributes = geometry.attributes;\n\n\t\tvar positions = attributes.position.array;\n\t\tvar normals = attributes.normal !== undefined ? attributes.normal.array : undefined;\n\t\tvar colors = attributes.color !== undefined ? attributes.color.array : undefined;\n\t\tvar uvs = attributes.uv !== undefined ? attributes.uv.array : undefined;\n\t\tvar uvs2 = attributes.uv2 !== undefined ? attributes.uv2.array : undefined;\n\n\t\tif ( uvs2 !== undefined ) this.faceVertexUvs[ 1 ] = [];\n\n\t\tvar tempNormals = [];\n\t\tvar tempUVs = [];\n\t\tvar tempUVs2 = [];\n\n\t\tfor ( var i = 0, j = 0; i < positions.length; i += 3, j += 2 ) {\n\n\t\t\tscope.vertices.push( new Vector3( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ) );\n\n\t\t\tif ( normals !== undefined ) {\n\n\t\t\t\ttempNormals.push( new Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) );\n\n\t\t\t}\n\n\t\t\tif ( colors !== undefined ) {\n\n\t\t\t\tscope.colors.push( new Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) );\n\n\t\t\t}\n\n\t\t\tif ( uvs !== undefined ) {\n\n\t\t\t\ttempUVs.push( new Vector2( uvs[ j ], uvs[ j + 1 ] ) );\n\n\t\t\t}\n\n\t\t\tif ( uvs2 !== undefined ) {\n\n\t\t\t\ttempUVs2.push( new Vector2( uvs2[ j ], uvs2[ j + 1 ] ) );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction addFace( a, b, c, materialIndex ) {\n\n\t\t\tvar vertexNormals = normals !== undefined ? [ tempNormals[ a ].clone(), tempNormals[ b ].clone(), tempNormals[ c ].clone() ] : [];\n\t\t\tvar vertexColors = colors !== undefined ? [ scope.colors[ a ].clone(), scope.colors[ b ].clone(), scope.colors[ c ].clone() ] : [];\n\n\t\t\tvar face = new Face3( a, b, c, vertexNormals, vertexColors, materialIndex );\n\n\t\t\tscope.faces.push( face );\n\n\t\t\tif ( uvs !== undefined ) {\n\n\t\t\t\tscope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] );\n\n\t\t\t}\n\n\t\t\tif ( uvs2 !== undefined ) {\n\n\t\t\t\tscope.faceVertexUvs[ 1 ].push( [ tempUVs2[ a ].clone(), tempUVs2[ b ].clone(), tempUVs2[ c ].clone() ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( indices !== undefined ) {\n\n\t\t\tvar groups = geometry.groups;\n\n\t\t\tif ( groups.length > 0 ) {\n\n\t\t\t\tfor ( var i = 0; i < groups.length; i ++ ) {\n\n\t\t\t\t\tvar group = groups[ i ];\n\n\t\t\t\t\tvar start = group.start;\n\t\t\t\t\tvar count = group.count;\n\n\t\t\t\t\tfor ( var j = start, jl = start + count; j < jl; j += 3 ) {\n\n\t\t\t\t\t\taddFace( indices[ j ], indices[ j + 1 ], indices[ j + 2 ], group.materialIndex );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tfor ( var i = 0; i < indices.length; i += 3 ) {\n\n\t\t\t\t\taddFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tfor ( var i = 0; i < positions.length / 3; i += 3 ) {\n\n\t\t\t\taddFace( i, i + 1, i + 2 );\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.computeFaceNormals();\n\n\t\tif ( geometry.boundingBox !== null ) {\n\n\t\t\tthis.boundingBox = geometry.boundingBox.clone();\n\n\t\t}\n\n\t\tif ( geometry.boundingSphere !== null ) {\n\n\t\t\tthis.boundingSphere = geometry.boundingSphere.clone();\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tcenter: function () {\n\n\t\tthis.computeBoundingBox();\n\n\t\tvar offset = this.boundingBox.getCenter().negate();\n\n\t\tthis.translate( offset.x, offset.y, offset.z );\n\n\t\treturn offset;\n\n\t},\n\n\tnormalize: function () {\n\n\t\tthis.computeBoundingSphere();\n\n\t\tvar center = this.boundingSphere.center;\n\t\tvar radius = this.boundingSphere.radius;\n\n\t\tvar s = radius === 0 ? 1 : 1.0 / radius;\n\n\t\tvar matrix = new Matrix4();\n\t\tmatrix.set(\n\t\t\ts, 0, 0, - s * center.x,\n\t\t\t0, s, 0, - s * center.y,\n\t\t\t0, 0, s, - s * center.z,\n\t\t\t0, 0, 0, 1\n\t\t);\n\n\t\tthis.applyMatrix( matrix );\n\n\t\treturn this;\n\n\t},\n\n\tcomputeFaceNormals: function () {\n\n\t\tvar cb = new Vector3(), ab = new Vector3();\n\n\t\tfor ( var f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\tvar face = this.faces[ f ];\n\n\t\t\tvar vA = this.vertices[ face.a ];\n\t\t\tvar vB = this.vertices[ face.b ];\n\t\t\tvar vC = this.vertices[ face.c ];\n\n\t\t\tcb.subVectors( vC, vB );\n\t\t\tab.subVectors( vA, vB );\n\t\t\tcb.cross( ab );\n\n\t\t\tcb.normalize();\n\n\t\t\tface.normal.copy( cb );\n\n\t\t}\n\n\t},\n\n\tcomputeVertexNormals: function ( areaWeighted ) {\n\n\t\tif ( areaWeighted === undefined ) areaWeighted = true;\n\n\t\tvar v, vl, f, fl, face, vertices;\n\n\t\tvertices = new Array( this.vertices.length );\n\n\t\tfor ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {\n\n\t\t\tvertices[ v ] = new Vector3();\n\n\t\t}\n\n\t\tif ( areaWeighted ) {\n\n\t\t\t// vertex normals weighted by triangle areas\n\t\t\t// http://www.iquilezles.org/www/articles/normals/normals.htm\n\n\t\t\tvar vA, vB, vC;\n\t\t\tvar cb = new Vector3(), ab = new Vector3();\n\n\t\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\t\tface = this.faces[ f ];\n\n\t\t\t\tvA = this.vertices[ face.a ];\n\t\t\t\tvB = this.vertices[ face.b ];\n\t\t\t\tvC = this.vertices[ face.c ];\n\n\t\t\t\tcb.subVectors( vC, vB );\n\t\t\t\tab.subVectors( vA, vB );\n\t\t\t\tcb.cross( ab );\n\n\t\t\t\tvertices[ face.a ].add( cb );\n\t\t\t\tvertices[ face.b ].add( cb );\n\t\t\t\tvertices[ face.c ].add( cb );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tthis.computeFaceNormals();\n\n\t\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\t\tface = this.faces[ f ];\n\n\t\t\t\tvertices[ face.a ].add( face.normal );\n\t\t\t\tvertices[ face.b ].add( face.normal );\n\t\t\t\tvertices[ face.c ].add( face.normal );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfor ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {\n\n\t\t\tvertices[ v ].normalize();\n\n\t\t}\n\n\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\tface = this.faces[ f ];\n\n\t\t\tvar vertexNormals = face.vertexNormals;\n\n\t\t\tif ( vertexNormals.length === 3 ) {\n\n\t\t\t\tvertexNormals[ 0 ].copy( vertices[ face.a ] );\n\t\t\t\tvertexNormals[ 1 ].copy( vertices[ face.b ] );\n\t\t\t\tvertexNormals[ 2 ].copy( vertices[ face.c ] );\n\n\t\t\t} else {\n\n\t\t\t\tvertexNormals[ 0 ] = vertices[ face.a ].clone();\n\t\t\t\tvertexNormals[ 1 ] = vertices[ face.b ].clone();\n\t\t\t\tvertexNormals[ 2 ] = vertices[ face.c ].clone();\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( this.faces.length > 0 ) {\n\n\t\t\tthis.normalsNeedUpdate = true;\n\n\t\t}\n\n\t},\n\n\tcomputeFlatVertexNormals: function () {\n\n\t\tvar f, fl, face;\n\n\t\tthis.computeFaceNormals();\n\n\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\tface = this.faces[ f ];\n\n\t\t\tvar vertexNormals = face.vertexNormals;\n\n\t\t\tif ( vertexNormals.length === 3 ) {\n\n\t\t\t\tvertexNormals[ 0 ].copy( face.normal );\n\t\t\t\tvertexNormals[ 1 ].copy( face.normal );\n\t\t\t\tvertexNormals[ 2 ].copy( face.normal );\n\n\t\t\t} else {\n\n\t\t\t\tvertexNormals[ 0 ] = face.normal.clone();\n\t\t\t\tvertexNormals[ 1 ] = face.normal.clone();\n\t\t\t\tvertexNormals[ 2 ] = face.normal.clone();\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( this.faces.length > 0 ) {\n\n\t\t\tthis.normalsNeedUpdate = true;\n\n\t\t}\n\n\t},\n\n\tcomputeMorphNormals: function () {\n\n\t\tvar i, il, f, fl, face;\n\n\t\t// save original normals\n\t\t// - create temp variables on first access\n\t\t// otherwise just copy (for faster repeated calls)\n\n\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\tface = this.faces[ f ];\n\n\t\t\tif ( ! face.__originalFaceNormal ) {\n\n\t\t\t\tface.__originalFaceNormal = face.normal.clone();\n\n\t\t\t} else {\n\n\t\t\t\tface.__originalFaceNormal.copy( face.normal );\n\n\t\t\t}\n\n\t\t\tif ( ! face.__originalVertexNormals ) face.__originalVertexNormals = [];\n\n\t\t\tfor ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) {\n\n\t\t\t\tif ( ! face.__originalVertexNormals[ i ] ) {\n\n\t\t\t\t\tface.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone();\n\n\t\t\t\t} else {\n\n\t\t\t\t\tface.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t// use temp geometry to compute face and vertex normals for each morph\n\n\t\tvar tmpGeo = new Geometry();\n\t\ttmpGeo.faces = this.faces;\n\n\t\tfor ( i = 0, il = this.morphTargets.length; i < il; i ++ ) {\n\n\t\t\t// create on first access\n\n\t\t\tif ( ! this.morphNormals[ i ] ) {\n\n\t\t\t\tthis.morphNormals[ i ] = {};\n\t\t\t\tthis.morphNormals[ i ].faceNormals = [];\n\t\t\t\tthis.morphNormals[ i ].vertexNormals = [];\n\n\t\t\t\tvar dstNormalsFace = this.morphNormals[ i ].faceNormals;\n\t\t\t\tvar dstNormalsVertex = this.morphNormals[ i ].vertexNormals;\n\n\t\t\t\tvar faceNormal, vertexNormals;\n\n\t\t\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\t\t\tfaceNormal = new Vector3();\n\t\t\t\t\tvertexNormals = { a: new Vector3(), b: new Vector3(), c: new Vector3() };\n\n\t\t\t\t\tdstNormalsFace.push( faceNormal );\n\t\t\t\t\tdstNormalsVertex.push( vertexNormals );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tvar morphNormals = this.morphNormals[ i ];\n\n\t\t\t// set vertices to morph target\n\n\t\t\ttmpGeo.vertices = this.morphTargets[ i ].vertices;\n\n\t\t\t// compute morph normals\n\n\t\t\ttmpGeo.computeFaceNormals();\n\t\t\ttmpGeo.computeVertexNormals();\n\n\t\t\t// store morph normals\n\n\t\t\tvar faceNormal, vertexNormals;\n\n\t\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\t\tface = this.faces[ f ];\n\n\t\t\t\tfaceNormal = morphNormals.faceNormals[ f ];\n\t\t\t\tvertexNormals = morphNormals.vertexNormals[ f ];\n\n\t\t\t\tfaceNormal.copy( face.normal );\n\n\t\t\t\tvertexNormals.a.copy( face.vertexNormals[ 0 ] );\n\t\t\t\tvertexNormals.b.copy( face.vertexNormals[ 1 ] );\n\t\t\t\tvertexNormals.c.copy( face.vertexNormals[ 2 ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// restore original normals\n\n\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\tface = this.faces[ f ];\n\n\t\t\tface.normal = face.__originalFaceNormal;\n\t\t\tface.vertexNormals = face.__originalVertexNormals;\n\n\t\t}\n\n\t},\n\n\tcomputeLineDistances: function () {\n\n\t\tvar d = 0;\n\t\tvar vertices = this.vertices;\n\n\t\tfor ( var i = 0, il = vertices.length; i < il; i ++ ) {\n\n\t\t\tif ( i > 0 ) {\n\n\t\t\t\td += vertices[ i ].distanceTo( vertices[ i - 1 ] );\n\n\t\t\t}\n\n\t\t\tthis.lineDistances[ i ] = d;\n\n\t\t}\n\n\t},\n\n\tcomputeBoundingBox: function () {\n\n\t\tif ( this.boundingBox === null ) {\n\n\t\t\tthis.boundingBox = new Box3();\n\n\t\t}\n\n\t\tthis.boundingBox.setFromPoints( this.vertices );\n\n\t},\n\n\tcomputeBoundingSphere: function () {\n\n\t\tif ( this.boundingSphere === null ) {\n\n\t\t\tthis.boundingSphere = new Sphere();\n\n\t\t}\n\n\t\tthis.boundingSphere.setFromPoints( this.vertices );\n\n\t},\n\n\tmerge: function ( geometry, matrix, materialIndexOffset ) {\n\n\t\tif ( ( geometry && geometry.isGeometry ) === false ) {\n\n\t\t\tconsole.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry );\n\t\t\treturn;\n\n\t\t}\n\n\t\tvar normalMatrix,\n\t\tvertexOffset = this.vertices.length,\n\t\tvertices1 = this.vertices,\n\t\tvertices2 = geometry.vertices,\n\t\tfaces1 = this.faces,\n\t\tfaces2 = geometry.faces,\n\t\tuvs1 = this.faceVertexUvs[ 0 ],\n\t\tuvs2 = geometry.faceVertexUvs[ 0 ],\n\t\tcolors1 = this.colors,\n\t\tcolors2 = geometry.colors;\n\n\t\tif ( materialIndexOffset === undefined ) materialIndexOffset = 0;\n\n\t\tif ( matrix !== undefined ) {\n\n\t\t\tnormalMatrix = new Matrix3().getNormalMatrix( matrix );\n\n\t\t}\n\n\t\t// vertices\n\n\t\tfor ( var i = 0, il = vertices2.length; i < il; i ++ ) {\n\n\t\t\tvar vertex = vertices2[ i ];\n\n\t\t\tvar vertexCopy = vertex.clone();\n\n\t\t\tif ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix );\n\n\t\t\tvertices1.push( vertexCopy );\n\n\t\t}\n\n\t\t// colors\n\n\t\tfor ( var i = 0, il = colors2.length; i < il; i ++ ) {\n\n\t\t\tcolors1.push( colors2[ i ].clone() );\n\n\t\t}\n\n\t\t// faces\n\n\t\tfor ( i = 0, il = faces2.length; i < il; i ++ ) {\n\n\t\t\tvar face = faces2[ i ], faceCopy, normal, color,\n\t\t\tfaceVertexNormals = face.vertexNormals,\n\t\t\tfaceVertexColors = face.vertexColors;\n\n\t\t\tfaceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );\n\t\t\tfaceCopy.normal.copy( face.normal );\n\n\t\t\tif ( normalMatrix !== undefined ) {\n\n\t\t\t\tfaceCopy.normal.applyMatrix3( normalMatrix ).normalize();\n\n\t\t\t}\n\n\t\t\tfor ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {\n\n\t\t\t\tnormal = faceVertexNormals[ j ].clone();\n\n\t\t\t\tif ( normalMatrix !== undefined ) {\n\n\t\t\t\t\tnormal.applyMatrix3( normalMatrix ).normalize();\n\n\t\t\t\t}\n\n\t\t\t\tfaceCopy.vertexNormals.push( normal );\n\n\t\t\t}\n\n\t\t\tfaceCopy.color.copy( face.color );\n\n\t\t\tfor ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {\n\n\t\t\t\tcolor = faceVertexColors[ j ];\n\t\t\t\tfaceCopy.vertexColors.push( color.clone() );\n\n\t\t\t}\n\n\t\t\tfaceCopy.materialIndex = face.materialIndex + materialIndexOffset;\n\n\t\t\tfaces1.push( faceCopy );\n\n\t\t}\n\n\t\t// uvs\n\n\t\tfor ( i = 0, il = uvs2.length; i < il; i ++ ) {\n\n\t\t\tvar uv = uvs2[ i ], uvCopy = [];\n\n\t\t\tif ( uv === undefined ) {\n\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tfor ( var j = 0, jl = uv.length; j < jl; j ++ ) {\n\n\t\t\t\tuvCopy.push( uv[ j ].clone() );\n\n\t\t\t}\n\n\t\t\tuvs1.push( uvCopy );\n\n\t\t}\n\n\t},\n\n\tmergeMesh: function ( mesh ) {\n\n\t\tif ( ( mesh && mesh.isMesh ) === false ) {\n\n\t\t\tconsole.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh );\n\t\t\treturn;\n\n\t\t}\n\n\t\tmesh.matrixAutoUpdate && mesh.updateMatrix();\n\n\t\tthis.merge( mesh.geometry, mesh.matrix );\n\n\t},\n\n\t/*\n\t * Checks for duplicate vertices with hashmap.\n\t * Duplicated vertices are removed\n\t * and faces' vertices are updated.\n\t */\n\n\tmergeVertices: function () {\n\n\t\tvar verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique)\n\t\tvar unique = [], changes = [];\n\n\t\tvar v, key;\n\t\tvar precisionPoints = 4; // number of decimal points, e.g. 4 for epsilon of 0.0001\n\t\tvar precision = Math.pow( 10, precisionPoints );\n\t\tvar i, il, face;\n\t\tvar indices, j, jl;\n\n\t\tfor ( i = 0, il = this.vertices.length; i < il; i ++ ) {\n\n\t\t\tv = this.vertices[ i ];\n\t\t\tkey = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision );\n\n\t\t\tif ( verticesMap[ key ] === undefined ) {\n\n\t\t\t\tverticesMap[ key ] = i;\n\t\t\t\tunique.push( this.vertices[ i ] );\n\t\t\t\tchanges[ i ] = unique.length - 1;\n\n\t\t\t} else {\n\n\t\t\t\t//console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]);\n\t\t\t\tchanges[ i ] = changes[ verticesMap[ key ] ];\n\n\t\t\t}\n\n\t\t}\n\n\n\t\t// if faces are completely degenerate after merging vertices, we\n\t\t// have to remove them from the geometry.\n\t\tvar faceIndicesToRemove = [];\n\n\t\tfor ( i = 0, il = this.faces.length; i < il; i ++ ) {\n\n\t\t\tface = this.faces[ i ];\n\n\t\t\tface.a = changes[ face.a ];\n\t\t\tface.b = changes[ face.b ];\n\t\t\tface.c = changes[ face.c ];\n\n\t\t\tindices = [ face.a, face.b, face.c ];\n\n\t\t\t// if any duplicate vertices are found in a Face3\n\t\t\t// we have to remove the face as nothing can be saved\n\t\t\tfor ( var n = 0; n < 3; n ++ ) {\n\n\t\t\t\tif ( indices[ n ] === indices[ ( n + 1 ) % 3 ] ) {\n\n\t\t\t\t\tfaceIndicesToRemove.push( i );\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfor ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) {\n\n\t\t\tvar idx = faceIndicesToRemove[ i ];\n\n\t\t\tthis.faces.splice( idx, 1 );\n\n\t\t\tfor ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {\n\n\t\t\t\tthis.faceVertexUvs[ j ].splice( idx, 1 );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Use unique set of vertices\n\n\t\tvar diff = this.vertices.length - unique.length;\n\t\tthis.vertices = unique;\n\t\treturn diff;\n\n\t},\n\n\tsortFacesByMaterialIndex: function () {\n\n\t\tvar faces = this.faces;\n\t\tvar length = faces.length;\n\n\t\t// tag faces\n\n\t\tfor ( var i = 0; i < length; i ++ ) {\n\n\t\t\tfaces[ i ]._id = i;\n\n\t\t}\n\n\t\t// sort faces\n\n\t\tfunction materialIndexSort( a, b ) {\n\n\t\t\treturn a.materialIndex - b.materialIndex;\n\n\t\t}\n\n\t\tfaces.sort( materialIndexSort );\n\n\t\t// sort uvs\n\n\t\tvar uvs1 = this.faceVertexUvs[ 0 ];\n\t\tvar uvs2 = this.faceVertexUvs[ 1 ];\n\n\t\tvar newUvs1, newUvs2;\n\n\t\tif ( uvs1 && uvs1.length === length ) newUvs1 = [];\n\t\tif ( uvs2 && uvs2.length === length ) newUvs2 = [];\n\n\t\tfor ( var i = 0; i < length; i ++ ) {\n\n\t\t\tvar id = faces[ i ]._id;\n\n\t\t\tif ( newUvs1 ) newUvs1.push( uvs1[ id ] );\n\t\t\tif ( newUvs2 ) newUvs2.push( uvs2[ id ] );\n\n\t\t}\n\n\t\tif ( newUvs1 ) this.faceVertexUvs[ 0 ] = newUvs1;\n\t\tif ( newUvs2 ) this.faceVertexUvs[ 1 ] = newUvs2;\n\n\t},\n\n\ttoJSON: function () {\n\n\t\tvar data = {\n\t\t\tmetadata: {\n\t\t\t\tversion: 4.4,\n\t\t\t\ttype: 'Geometry',\n\t\t\t\tgenerator: 'Geometry.toJSON'\n\t\t\t}\n\t\t};\n\n\t\t// standard Geometry serialization\n\n\t\tdata.uuid = this.uuid;\n\t\tdata.type = this.type;\n\t\tif ( this.name !== '' ) data.name = this.name;\n\n\t\tif ( this.parameters !== undefined ) {\n\n\t\t\tvar parameters = this.parameters;\n\n\t\t\tfor ( var key in parameters ) {\n\n\t\t\t\tif ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tvar vertices = [];\n\n\t\tfor ( var i = 0; i < this.vertices.length; i ++ ) {\n\n\t\t\tvar vertex = this.vertices[ i ];\n\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t}\n\n\t\tvar faces = [];\n\t\tvar normals = [];\n\t\tvar normalsHash = {};\n\t\tvar colors = [];\n\t\tvar colorsHash = {};\n\t\tvar uvs = [];\n\t\tvar uvsHash = {};\n\n\t\tfor ( var i = 0; i < this.faces.length; i ++ ) {\n\n\t\t\tvar face = this.faces[ i ];\n\n\t\t\tvar hasMaterial = true;\n\t\t\tvar hasFaceUv = false; // deprecated\n\t\t\tvar hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i ] !== undefined;\n\t\t\tvar hasFaceNormal = face.normal.length() > 0;\n\t\t\tvar hasFaceVertexNormal = face.vertexNormals.length > 0;\n\t\t\tvar hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1;\n\t\t\tvar hasFaceVertexColor = face.vertexColors.length > 0;\n\n\t\t\tvar faceType = 0;\n\n\t\t\tfaceType = setBit( faceType, 0, 0 ); // isQuad\n\t\t\tfaceType = setBit( faceType, 1, hasMaterial );\n\t\t\tfaceType = setBit( faceType, 2, hasFaceUv );\n\t\t\tfaceType = setBit( faceType, 3, hasFaceVertexUv );\n\t\t\tfaceType = setBit( faceType, 4, hasFaceNormal );\n\t\t\tfaceType = setBit( faceType, 5, hasFaceVertexNormal );\n\t\t\tfaceType = setBit( faceType, 6, hasFaceColor );\n\t\t\tfaceType = setBit( faceType, 7, hasFaceVertexColor );\n\n\t\t\tfaces.push( faceType );\n\t\t\tfaces.push( face.a, face.b, face.c );\n\t\t\tfaces.push( face.materialIndex );\n\n\t\t\tif ( hasFaceVertexUv ) {\n\n\t\t\t\tvar faceVertexUvs = this.faceVertexUvs[ 0 ][ i ];\n\n\t\t\t\tfaces.push(\n\t\t\t\t\tgetUvIndex( faceVertexUvs[ 0 ] ),\n\t\t\t\t\tgetUvIndex( faceVertexUvs[ 1 ] ),\n\t\t\t\t\tgetUvIndex( faceVertexUvs[ 2 ] )\n\t\t\t\t);\n\n\t\t\t}\n\n\t\t\tif ( hasFaceNormal ) {\n\n\t\t\t\tfaces.push( getNormalIndex( face.normal ) );\n\n\t\t\t}\n\n\t\t\tif ( hasFaceVertexNormal ) {\n\n\t\t\t\tvar vertexNormals = face.vertexNormals;\n\n\t\t\t\tfaces.push(\n\t\t\t\t\tgetNormalIndex( vertexNormals[ 0 ] ),\n\t\t\t\t\tgetNormalIndex( vertexNormals[ 1 ] ),\n\t\t\t\t\tgetNormalIndex( vertexNormals[ 2 ] )\n\t\t\t\t);\n\n\t\t\t}\n\n\t\t\tif ( hasFaceColor ) {\n\n\t\t\t\tfaces.push( getColorIndex( face.color ) );\n\n\t\t\t}\n\n\t\t\tif ( hasFaceVertexColor ) {\n\n\t\t\t\tvar vertexColors = face.vertexColors;\n\n\t\t\t\tfaces.push(\n\t\t\t\t\tgetColorIndex( vertexColors[ 0 ] ),\n\t\t\t\t\tgetColorIndex( vertexColors[ 1 ] ),\n\t\t\t\t\tgetColorIndex( vertexColors[ 2 ] )\n\t\t\t\t);\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction setBit( value, position, enabled ) {\n\n\t\t\treturn enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position ) );\n\n\t\t}\n\n\t\tfunction getNormalIndex( normal ) {\n\n\t\t\tvar hash = normal.x.toString() + normal.y.toString() + normal.z.toString();\n\n\t\t\tif ( normalsHash[ hash ] !== undefined ) {\n\n\t\t\t\treturn normalsHash[ hash ];\n\n\t\t\t}\n\n\t\t\tnormalsHash[ hash ] = normals.length / 3;\n\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\treturn normalsHash[ hash ];\n\n\t\t}\n\n\t\tfunction getColorIndex( color ) {\n\n\t\t\tvar hash = color.r.toString() + color.g.toString() + color.b.toString();\n\n\t\t\tif ( colorsHash[ hash ] !== undefined ) {\n\n\t\t\t\treturn colorsHash[ hash ];\n\n\t\t\t}\n\n\t\t\tcolorsHash[ hash ] = colors.length;\n\t\t\tcolors.push( color.getHex() );\n\n\t\t\treturn colorsHash[ hash ];\n\n\t\t}\n\n\t\tfunction getUvIndex( uv ) {\n\n\t\t\tvar hash = uv.x.toString() + uv.y.toString();\n\n\t\t\tif ( uvsHash[ hash ] !== undefined ) {\n\n\t\t\t\treturn uvsHash[ hash ];\n\n\t\t\t}\n\n\t\t\tuvsHash[ hash ] = uvs.length / 2;\n\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t\treturn uvsHash[ hash ];\n\n\t\t}\n\n\t\tdata.data = {};\n\n\t\tdata.data.vertices = vertices;\n\t\tdata.data.normals = normals;\n\t\tif ( colors.length > 0 ) data.data.colors = colors;\n\t\tif ( uvs.length > 0 ) data.data.uvs = [ uvs ]; // temporal backward compatibility\n\t\tdata.data.faces = faces;\n\n\t\treturn data;\n\n\t},\n\n\tclone: function () {\n\n\t\t/*\n\t\t// Handle primitives\n\n\t\tvar parameters = this.parameters;\n\n\t\tif ( parameters !== undefined ) {\n\n\t\t\tvar values = [];\n\n\t\t\tfor ( var key in parameters ) {\n\n\t\t\t\tvalues.push( parameters[ key ] );\n\n\t\t\t}\n\n\t\t\tvar geometry = Object.create( this.constructor.prototype );\n\t\t\tthis.constructor.apply( geometry, values );\n\t\t\treturn geometry;\n\n\t\t}\n\n\t\treturn new this.constructor().copy( this );\n\t\t*/\n\n\t\treturn new Geometry().copy( this );\n\n\t},\n\n\tcopy: function ( source ) {\n\n\t\tvar i, il, j, jl, k, kl;\n\n\t\t// reset\n\n\t\tthis.vertices = [];\n\t\tthis.colors = [];\n\t\tthis.faces = [];\n\t\tthis.faceVertexUvs = [[]];\n\t\tthis.morphTargets = [];\n\t\tthis.morphNormals = [];\n\t\tthis.skinWeights = [];\n\t\tthis.skinIndices = [];\n\t\tthis.lineDistances = [];\n\t\tthis.boundingBox = null;\n\t\tthis.boundingSphere = null;\n\n\t\t// name\n\n\t\tthis.name = source.name;\n\n\t\t// vertices\n\n\t\tvar vertices = source.vertices;\n\n\t\tfor ( i = 0, il = vertices.length; i < il; i ++ ) {\n\n\t\t\tthis.vertices.push( vertices[ i ].clone() );\n\n\t\t}\n\n\t\t// colors\n\n\t\tvar colors = source.colors;\n\n\t\tfor ( i = 0, il = colors.length; i < il; i ++ ) {\n\n\t\t\tthis.colors.push( colors[ i ].clone() );\n\n\t\t}\n\n\t\t// faces\n\n\t\tvar faces = source.faces;\n\n\t\tfor ( i = 0, il = faces.length; i < il; i ++ ) {\n\n\t\t\tthis.faces.push( faces[ i ].clone() );\n\n\t\t}\n\n\t\t// face vertex uvs\n\n\t\tfor ( i = 0, il = source.faceVertexUvs.length; i < il; i ++ ) {\n\n\t\t\tvar faceVertexUvs = source.faceVertexUvs[ i ];\n\n\t\t\tif ( this.faceVertexUvs[ i ] === undefined ) {\n\n\t\t\t\tthis.faceVertexUvs[ i ] = [];\n\n\t\t\t}\n\n\t\t\tfor ( j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) {\n\n\t\t\t\tvar uvs = faceVertexUvs[ j ], uvsCopy = [];\n\n\t\t\t\tfor ( k = 0, kl = uvs.length; k < kl; k ++ ) {\n\n\t\t\t\t\tvar uv = uvs[ k ];\n\n\t\t\t\t\tuvsCopy.push( uv.clone() );\n\n\t\t\t\t}\n\n\t\t\t\tthis.faceVertexUvs[ i ].push( uvsCopy );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// morph targets\n\n\t\tvar morphTargets = source.morphTargets;\n\n\t\tfor ( i = 0, il = morphTargets.length; i < il; i ++ ) {\n\n\t\t\tvar morphTarget = {};\n\t\t\tmorphTarget.name = morphTargets[ i ].name;\n\n\t\t\t// vertices\n\n\t\t\tif ( morphTargets[ i ].vertices !== undefined ) {\n\n\t\t\t\tmorphTarget.vertices = [];\n\n\t\t\t\tfor ( j = 0, jl = morphTargets[ i ].vertices.length; j < jl; j ++ ) {\n\n\t\t\t\t\tmorphTarget.vertices.push( morphTargets[ i ].vertices[ j ].clone() );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// normals\n\n\t\t\tif ( morphTargets[ i ].normals !== undefined ) {\n\n\t\t\t\tmorphTarget.normals = [];\n\n\t\t\t\tfor ( j = 0, jl = morphTargets[ i ].normals.length; j < jl; j ++ ) {\n\n\t\t\t\t\tmorphTarget.normals.push( morphTargets[ i ].normals[ j ].clone() );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.morphTargets.push( morphTarget );\n\n\t\t}\n\n\t\t// morph normals\n\n\t\tvar morphNormals = source.morphNormals;\n\n\t\tfor ( i = 0, il = morphNormals.length; i < il; i ++ ) {\n\n\t\t\tvar morphNormal = {};\n\n\t\t\t// vertex normals\n\n\t\t\tif ( morphNormals[ i ].vertexNormals !== undefined ) {\n\n\t\t\t\tmorphNormal.vertexNormals = [];\n\n\t\t\t\tfor ( j = 0, jl = morphNormals[ i ].vertexNormals.length; j < jl; j ++ ) {\n\n\t\t\t\t\tvar srcVertexNormal = morphNormals[ i ].vertexNormals[ j ];\n\t\t\t\t\tvar destVertexNormal = {};\n\n\t\t\t\t\tdestVertexNormal.a = srcVertexNormal.a.clone();\n\t\t\t\t\tdestVertexNormal.b = srcVertexNormal.b.clone();\n\t\t\t\t\tdestVertexNormal.c = srcVertexNormal.c.clone();\n\n\t\t\t\t\tmorphNormal.vertexNormals.push( destVertexNormal );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// face normals\n\n\t\t\tif ( morphNormals[ i ].faceNormals !== undefined ) {\n\n\t\t\t\tmorphNormal.faceNormals = [];\n\n\t\t\t\tfor ( j = 0, jl = morphNormals[ i ].faceNormals.length; j < jl; j ++ ) {\n\n\t\t\t\t\tmorphNormal.faceNormals.push( morphNormals[ i ].faceNormals[ j ].clone() );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.morphNormals.push( morphNormal );\n\n\t\t}\n\n\t\t// skin weights\n\n\t\tvar skinWeights = source.skinWeights;\n\n\t\tfor ( i = 0, il = skinWeights.length; i < il; i ++ ) {\n\n\t\t\tthis.skinWeights.push( skinWeights[ i ].clone() );\n\n\t\t}\n\n\t\t// skin indices\n\n\t\tvar skinIndices = source.skinIndices;\n\n\t\tfor ( i = 0, il = skinIndices.length; i < il; i ++ ) {\n\n\t\t\tthis.skinIndices.push( skinIndices[ i ].clone() );\n\n\t\t}\n\n\t\t// line distances\n\n\t\tvar lineDistances = source.lineDistances;\n\n\t\tfor ( i = 0, il = lineDistances.length; i < il; i ++ ) {\n\n\t\t\tthis.lineDistances.push( lineDistances[ i ] );\n\n\t\t}\n\n\t\t// bounding box\n\n\t\tvar boundingBox = source.boundingBox;\n\n\t\tif ( boundingBox !== null ) {\n\n\t\t\tthis.boundingBox = boundingBox.clone();\n\n\t\t}\n\n\t\t// bounding sphere\n\n\t\tvar boundingSphere = source.boundingSphere;\n\n\t\tif ( boundingSphere !== null ) {\n\n\t\t\tthis.boundingSphere = boundingSphere.clone();\n\n\t\t}\n\n\t\t// update flags\n\n\t\tthis.elementsNeedUpdate = source.elementsNeedUpdate;\n\t\tthis.verticesNeedUpdate = source.verticesNeedUpdate;\n\t\tthis.uvsNeedUpdate = source.uvsNeedUpdate;\n\t\tthis.normalsNeedUpdate = source.normalsNeedUpdate;\n\t\tthis.colorsNeedUpdate = source.colorsNeedUpdate;\n\t\tthis.lineDistancesNeedUpdate = source.lineDistancesNeedUpdate;\n\t\tthis.groupsNeedUpdate = source.groupsNeedUpdate;\n\n\t\treturn this;\n\n\t},\n\n\tdispose: function () {\n\n\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t}\n\n};\n\nObject.assign( Geometry.prototype, EventDispatcher.prototype );\n\n/**\n * @author alteredq / http://alteredqualia.com/\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction BufferGeometry() {\n\n\tObject.defineProperty( this, 'id', { value: GeometryIdCount() } );\n\n\tthis.uuid = _Math.generateUUID();\n\n\tthis.name = '';\n\tthis.type = 'BufferGeometry';\n\n\tthis.index = null;\n\tthis.attributes = {};\n\n\tthis.morphAttributes = {};\n\n\tthis.groups = [];\n\n\tthis.boundingBox = null;\n\tthis.boundingSphere = null;\n\n\tthis.drawRange = { start: 0, count: Infinity };\n\n}\n\nBufferGeometry.prototype = {\n\n\tconstructor: BufferGeometry,\n\n\tisBufferGeometry: true,\n\n\tgetIndex: function () {\n\n\t\treturn this.index;\n\n\t},\n\n\tsetIndex: function ( index ) {\n\n\t\tif ( Array.isArray( index ) ) {\n\n\t\t\tthis.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );\n\n\t\t} else {\n\n\t\t\tthis.index = index;\n\n\t\t}\n\n\t},\n\n\taddAttribute: function ( name, attribute ) {\n\n\t\tif ( ( attribute && attribute.isBufferAttribute ) === false && ( attribute && attribute.isInterleavedBufferAttribute ) === false ) {\n\n\t\t\tconsole.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );\n\n\t\t\tthis.addAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) );\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( name === 'index' ) {\n\n\t\t\tconsole.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' );\n\t\t\tthis.setIndex( attribute );\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis.attributes[ name ] = attribute;\n\n\t\treturn this;\n\n\t},\n\n\tgetAttribute: function ( name ) {\n\n\t\treturn this.attributes[ name ];\n\n\t},\n\n\tremoveAttribute: function ( name ) {\n\n\t\tdelete this.attributes[ name ];\n\n\t\treturn this;\n\n\t},\n\n\taddGroup: function ( start, count, materialIndex ) {\n\n\t\tthis.groups.push( {\n\n\t\t\tstart: start,\n\t\t\tcount: count,\n\t\t\tmaterialIndex: materialIndex !== undefined ? materialIndex : 0\n\n\t\t} );\n\n\t},\n\n\tclearGroups: function () {\n\n\t\tthis.groups = [];\n\n\t},\n\n\tsetDrawRange: function ( start, count ) {\n\n\t\tthis.drawRange.start = start;\n\t\tthis.drawRange.count = count;\n\n\t},\n\n\tapplyMatrix: function ( matrix ) {\n\n\t\tvar position = this.attributes.position;\n\n\t\tif ( position !== undefined ) {\n\n\t\t\tmatrix.applyToBufferAttribute( position );\n\t\t\tposition.needsUpdate = true;\n\n\t\t}\n\n\t\tvar normal = this.attributes.normal;\n\n\t\tif ( normal !== undefined ) {\n\n\t\t\tvar normalMatrix = new Matrix3().getNormalMatrix( matrix );\n\n\t\t\tnormalMatrix.applyToBufferAttribute( normal );\n\t\t\tnormal.needsUpdate = true;\n\n\t\t}\n\n\t\tif ( this.boundingBox !== null ) {\n\n\t\t\tthis.computeBoundingBox();\n\n\t\t}\n\n\t\tif ( this.boundingSphere !== null ) {\n\n\t\t\tthis.computeBoundingSphere();\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\trotateX: function () {\n\n\t\t// rotate geometry around world x-axis\n\n\t\tvar m1;\n\n\t\treturn function rotateX( angle ) {\n\n\t\t\tif ( m1 === undefined ) m1 = new Matrix4();\n\n\t\t\tm1.makeRotationX( angle );\n\n\t\t\tthis.applyMatrix( m1 );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\trotateY: function () {\n\n\t\t// rotate geometry around world y-axis\n\n\t\tvar m1;\n\n\t\treturn function rotateY( angle ) {\n\n\t\t\tif ( m1 === undefined ) m1 = new Matrix4();\n\n\t\t\tm1.makeRotationY( angle );\n\n\t\t\tthis.applyMatrix( m1 );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\trotateZ: function () {\n\n\t\t// rotate geometry around world z-axis\n\n\t\tvar m1;\n\n\t\treturn function rotateZ( angle ) {\n\n\t\t\tif ( m1 === undefined ) m1 = new Matrix4();\n\n\t\t\tm1.makeRotationZ( angle );\n\n\t\t\tthis.applyMatrix( m1 );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\ttranslate: function () {\n\n\t\t// translate geometry\n\n\t\tvar m1;\n\n\t\treturn function translate( x, y, z ) {\n\n\t\t\tif ( m1 === undefined ) m1 = new Matrix4();\n\n\t\t\tm1.makeTranslation( x, y, z );\n\n\t\t\tthis.applyMatrix( m1 );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\tscale: function () {\n\n\t\t// scale geometry\n\n\t\tvar m1;\n\n\t\treturn function scale( x, y, z ) {\n\n\t\t\tif ( m1 === undefined ) m1 = new Matrix4();\n\n\t\t\tm1.makeScale( x, y, z );\n\n\t\t\tthis.applyMatrix( m1 );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t}(),\n\n\tlookAt: function () {\n\n\t\tvar obj;\n\n\t\treturn function lookAt( vector ) {\n\n\t\t\tif ( obj === undefined ) obj = new Object3D();\n\n\t\t\tobj.lookAt( vector );\n\n\t\t\tobj.updateMatrix();\n\n\t\t\tthis.applyMatrix( obj.matrix );\n\n\t\t};\n\n\t}(),\n\n\tcenter: function () {\n\n\t\tthis.computeBoundingBox();\n\n\t\tvar offset = this.boundingBox.getCenter().negate();\n\n\t\tthis.translate( offset.x, offset.y, offset.z );\n\n\t\treturn offset;\n\n\t},\n\n\tsetFromObject: function ( object ) {\n\n\t\t// console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this );\n\n\t\tvar geometry = object.geometry;\n\n\t\tif ( object.isPoints || object.isLine ) {\n\n\t\t\tvar positions = new Float32BufferAttribute( geometry.vertices.length * 3, 3 );\n\t\t\tvar colors = new Float32BufferAttribute( geometry.colors.length * 3, 3 );\n\n\t\t\tthis.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) );\n\t\t\tthis.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) );\n\n\t\t\tif ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) {\n\n\t\t\t\tvar lineDistances = new Float32BufferAttribute( geometry.lineDistances.length, 1 );\n\n\t\t\t\tthis.addAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) );\n\n\t\t\t}\n\n\t\t\tif ( geometry.boundingSphere !== null ) {\n\n\t\t\t\tthis.boundingSphere = geometry.boundingSphere.clone();\n\n\t\t\t}\n\n\t\t\tif ( geometry.boundingBox !== null ) {\n\n\t\t\t\tthis.boundingBox = geometry.boundingBox.clone();\n\n\t\t\t}\n\n\t\t} else if ( object.isMesh ) {\n\n\t\t\tif ( geometry && geometry.isGeometry ) {\n\n\t\t\t\tthis.fromGeometry( geometry );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tupdateFromObject: function ( object ) {\n\n\t\tvar geometry = object.geometry;\n\n\t\tif ( object.isMesh ) {\n\n\t\t\tvar direct = geometry.__directGeometry;\n\n\t\t\tif ( geometry.elementsNeedUpdate === true ) {\n\n\t\t\t\tdirect = undefined;\n\t\t\t\tgeometry.elementsNeedUpdate = false;\n\n\t\t\t}\n\n\t\t\tif ( direct === undefined ) {\n\n\t\t\t\treturn this.fromGeometry( geometry );\n\n\t\t\t}\n\n\t\t\tdirect.verticesNeedUpdate = geometry.verticesNeedUpdate;\n\t\t\tdirect.normalsNeedUpdate = geometry.normalsNeedUpdate;\n\t\t\tdirect.colorsNeedUpdate = geometry.colorsNeedUpdate;\n\t\t\tdirect.uvsNeedUpdate = geometry.uvsNeedUpdate;\n\t\t\tdirect.groupsNeedUpdate = geometry.groupsNeedUpdate;\n\n\t\t\tgeometry.verticesNeedUpdate = false;\n\t\t\tgeometry.normalsNeedUpdate = false;\n\t\t\tgeometry.colorsNeedUpdate = false;\n\t\t\tgeometry.uvsNeedUpdate = false;\n\t\t\tgeometry.groupsNeedUpdate = false;\n\n\t\t\tgeometry = direct;\n\n\t\t}\n\n\t\tvar attribute;\n\n\t\tif ( geometry.verticesNeedUpdate === true ) {\n\n\t\t\tattribute = this.attributes.position;\n\n\t\t\tif ( attribute !== undefined ) {\n\n\t\t\t\tattribute.copyVector3sArray( geometry.vertices );\n\t\t\t\tattribute.needsUpdate = true;\n\n\t\t\t}\n\n\t\t\tgeometry.verticesNeedUpdate = false;\n\n\t\t}\n\n\t\tif ( geometry.normalsNeedUpdate === true ) {\n\n\t\t\tattribute = this.attributes.normal;\n\n\t\t\tif ( attribute !== undefined ) {\n\n\t\t\t\tattribute.copyVector3sArray( geometry.normals );\n\t\t\t\tattribute.needsUpdate = true;\n\n\t\t\t}\n\n\t\t\tgeometry.normalsNeedUpdate = false;\n\n\t\t}\n\n\t\tif ( geometry.colorsNeedUpdate === true ) {\n\n\t\t\tattribute = this.attributes.color;\n\n\t\t\tif ( attribute !== undefined ) {\n\n\t\t\t\tattribute.copyColorsArray( geometry.colors );\n\t\t\t\tattribute.needsUpdate = true;\n\n\t\t\t}\n\n\t\t\tgeometry.colorsNeedUpdate = false;\n\n\t\t}\n\n\t\tif ( geometry.uvsNeedUpdate ) {\n\n\t\t\tattribute = this.attributes.uv;\n\n\t\t\tif ( attribute !== undefined ) {\n\n\t\t\t\tattribute.copyVector2sArray( geometry.uvs );\n\t\t\t\tattribute.needsUpdate = true;\n\n\t\t\t}\n\n\t\t\tgeometry.uvsNeedUpdate = false;\n\n\t\t}\n\n\t\tif ( geometry.lineDistancesNeedUpdate ) {\n\n\t\t\tattribute = this.attributes.lineDistance;\n\n\t\t\tif ( attribute !== undefined ) {\n\n\t\t\t\tattribute.copyArray( geometry.lineDistances );\n\t\t\t\tattribute.needsUpdate = true;\n\n\t\t\t}\n\n\t\t\tgeometry.lineDistancesNeedUpdate = false;\n\n\t\t}\n\n\t\tif ( geometry.groupsNeedUpdate ) {\n\n\t\t\tgeometry.computeGroups( object.geometry );\n\t\t\tthis.groups = geometry.groups;\n\n\t\t\tgeometry.groupsNeedUpdate = false;\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tfromGeometry: function ( geometry ) {\n\n\t\tgeometry.__directGeometry = new DirectGeometry().fromGeometry( geometry );\n\n\t\treturn this.fromDirectGeometry( geometry.__directGeometry );\n\n\t},\n\n\tfromDirectGeometry: function ( geometry ) {\n\n\t\tvar positions = new Float32Array( geometry.vertices.length * 3 );\n\t\tthis.addAttribute( 'position', new BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) );\n\n\t\tif ( geometry.normals.length > 0 ) {\n\n\t\t\tvar normals = new Float32Array( geometry.normals.length * 3 );\n\t\t\tthis.addAttribute( 'normal', new BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) );\n\n\t\t}\n\n\t\tif ( geometry.colors.length > 0 ) {\n\n\t\t\tvar colors = new Float32Array( geometry.colors.length * 3 );\n\t\t\tthis.addAttribute( 'color', new BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) );\n\n\t\t}\n\n\t\tif ( geometry.uvs.length > 0 ) {\n\n\t\t\tvar uvs = new Float32Array( geometry.uvs.length * 2 );\n\t\t\tthis.addAttribute( 'uv', new BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) );\n\n\t\t}\n\n\t\tif ( geometry.uvs2.length > 0 ) {\n\n\t\t\tvar uvs2 = new Float32Array( geometry.uvs2.length * 2 );\n\t\t\tthis.addAttribute( 'uv2', new BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) );\n\n\t\t}\n\n\t\tif ( geometry.indices.length > 0 ) {\n\n\t\t\tvar TypeArray = arrayMax( geometry.indices ) > 65535 ? Uint32Array : Uint16Array;\n\t\t\tvar indices = new TypeArray( geometry.indices.length * 3 );\n\t\t\tthis.setIndex( new BufferAttribute( indices, 1 ).copyIndicesArray( geometry.indices ) );\n\n\t\t}\n\n\t\t// groups\n\n\t\tthis.groups = geometry.groups;\n\n\t\t// morphs\n\n\t\tfor ( var name in geometry.morphTargets ) {\n\n\t\t\tvar array = [];\n\t\t\tvar morphTargets = geometry.morphTargets[ name ];\n\n\t\t\tfor ( var i = 0, l = morphTargets.length; i < l; i ++ ) {\n\n\t\t\t\tvar morphTarget = morphTargets[ i ];\n\n\t\t\t\tvar attribute = new Float32BufferAttribute( morphTarget.length * 3, 3 );\n\n\t\t\t\tarray.push( attribute.copyVector3sArray( morphTarget ) );\n\n\t\t\t}\n\n\t\t\tthis.morphAttributes[ name ] = array;\n\n\t\t}\n\n\t\t// skinning\n\n\t\tif ( geometry.skinIndices.length > 0 ) {\n\n\t\t\tvar skinIndices = new Float32BufferAttribute( geometry.skinIndices.length * 4, 4 );\n\t\t\tthis.addAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) );\n\n\t\t}\n\n\t\tif ( geometry.skinWeights.length > 0 ) {\n\n\t\t\tvar skinWeights = new Float32BufferAttribute( geometry.skinWeights.length * 4, 4 );\n\t\t\tthis.addAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) );\n\n\t\t}\n\n\t\t//\n\n\t\tif ( geometry.boundingSphere !== null ) {\n\n\t\t\tthis.boundingSphere = geometry.boundingSphere.clone();\n\n\t\t}\n\n\t\tif ( geometry.boundingBox !== null ) {\n\n\t\t\tthis.boundingBox = geometry.boundingBox.clone();\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tcomputeBoundingBox: function () {\n\n\t\tif ( this.boundingBox === null ) {\n\n\t\t\tthis.boundingBox = new Box3();\n\n\t\t}\n\n\t\tvar position = this.attributes.position;\n\n\t\tif ( position !== undefined ) {\n\n\t\t\tthis.boundingBox.setFromBufferAttribute( position );\n\n\t\t} else {\n\n\t\t\tthis.boundingBox.makeEmpty();\n\n\t\t}\n\n\t\tif ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {\n\n\t\t\tconsole.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The \"position\" attribute is likely to have NaN values.', this );\n\n\t\t}\n\n\t},\n\n\tcomputeBoundingSphere: function () {\n\n\t\tvar box = new Box3();\n\t\tvar vector = new Vector3();\n\n\t\treturn function computeBoundingSphere() {\n\n\t\t\tif ( this.boundingSphere === null ) {\n\n\t\t\t\tthis.boundingSphere = new Sphere();\n\n\t\t\t}\n\n\t\t\tvar position = this.attributes.position;\n\n\t\t\tif ( position ) {\n\n\t\t\t\tvar center = this.boundingSphere.center;\n\n\t\t\t\tbox.setFromBufferAttribute( position );\n\t\t\t\tbox.getCenter( center );\n\n\t\t\t\t// hoping to find a boundingSphere with a radius smaller than the\n\t\t\t\t// boundingSphere of the boundingBox: sqrt(3) smaller in the best case\n\n\t\t\t\tvar maxRadiusSq = 0;\n\n\t\t\t\tfor ( var i = 0, il = position.count; i < il; i ++ ) {\n\n\t\t\t\t\tvector.x = position.getX( i );\n\t\t\t\t\tvector.y = position.getY( i );\n\t\t\t\t\tvector.z = position.getZ( i );\n\t\t\t\t\tmaxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );\n\n\t\t\t\t}\n\n\t\t\t\tthis.boundingSphere.radius = Math.sqrt( maxRadiusSq );\n\n\t\t\t\tif ( isNaN( this.boundingSphere.radius ) ) {\n\n\t\t\t\t\tconsole.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The \"position\" attribute is likely to have NaN values.', this );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t}(),\n\n\tcomputeFaceNormals: function () {\n\n\t\t// backwards compatibility\n\n\t},\n\n\tcomputeVertexNormals: function () {\n\n\t\tvar index = this.index;\n\t\tvar attributes = this.attributes;\n\t\tvar groups = this.groups;\n\n\t\tif ( attributes.position ) {\n\n\t\t\tvar positions = attributes.position.array;\n\n\t\t\tif ( attributes.normal === undefined ) {\n\n\t\t\t\tthis.addAttribute( 'normal', new BufferAttribute( new Float32Array( positions.length ), 3 ) );\n\n\t\t\t} else {\n\n\t\t\t\t// reset existing normals to zero\n\n\t\t\t\tvar array = attributes.normal.array;\n\n\t\t\t\tfor ( var i = 0, il = array.length; i < il; i ++ ) {\n\n\t\t\t\t\tarray[ i ] = 0;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tvar normals = attributes.normal.array;\n\n\t\t\tvar vA, vB, vC;\n\t\t\tvar pA = new Vector3(), pB = new Vector3(), pC = new Vector3();\n\t\t\tvar cb = new Vector3(), ab = new Vector3();\n\n\t\t\t// indexed elements\n\n\t\t\tif ( index ) {\n\n\t\t\t\tvar indices = index.array;\n\n\t\t\t\tif ( groups.length === 0 ) {\n\n\t\t\t\t\tthis.addGroup( 0, indices.length );\n\n\t\t\t\t}\n\n\t\t\t\tfor ( var j = 0, jl = groups.length; j < jl; ++ j ) {\n\n\t\t\t\t\tvar group = groups[ j ];\n\n\t\t\t\t\tvar start = group.start;\n\t\t\t\t\tvar count = group.count;\n\n\t\t\t\t\tfor ( var i = start, il = start + count; i < il; i += 3 ) {\n\n\t\t\t\t\t\tvA = indices[ i + 0 ] * 3;\n\t\t\t\t\t\tvB = indices[ i + 1 ] * 3;\n\t\t\t\t\t\tvC = indices[ i + 2 ] * 3;\n\n\t\t\t\t\t\tpA.fromArray( positions, vA );\n\t\t\t\t\t\tpB.fromArray( positions, vB );\n\t\t\t\t\t\tpC.fromArray( positions, vC );\n\n\t\t\t\t\t\tcb.subVectors( pC, pB );\n\t\t\t\t\t\tab.subVectors( pA, pB );\n\t\t\t\t\t\tcb.cross( ab );\n\n\t\t\t\t\t\tnormals[ vA ] += cb.x;\n\t\t\t\t\t\tnormals[ vA + 1 ] += cb.y;\n\t\t\t\t\t\tnormals[ vA + 2 ] += cb.z;\n\n\t\t\t\t\t\tnormals[ vB ] += cb.x;\n\t\t\t\t\t\tnormals[ vB + 1 ] += cb.y;\n\t\t\t\t\t\tnormals[ vB + 2 ] += cb.z;\n\n\t\t\t\t\t\tnormals[ vC ] += cb.x;\n\t\t\t\t\t\tnormals[ vC + 1 ] += cb.y;\n\t\t\t\t\t\tnormals[ vC + 2 ] += cb.z;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// non-indexed elements (unconnected triangle soup)\n\n\t\t\t\tfor ( var i = 0, il = positions.length; i < il; i += 9 ) {\n\n\t\t\t\t\tpA.fromArray( positions, i );\n\t\t\t\t\tpB.fromArray( positions, i + 3 );\n\t\t\t\t\tpC.fromArray( positions, i + 6 );\n\n\t\t\t\t\tcb.subVectors( pC, pB );\n\t\t\t\t\tab.subVectors( pA, pB );\n\t\t\t\t\tcb.cross( ab );\n\n\t\t\t\t\tnormals[ i ] = cb.x;\n\t\t\t\t\tnormals[ i + 1 ] = cb.y;\n\t\t\t\t\tnormals[ i + 2 ] = cb.z;\n\n\t\t\t\t\tnormals[ i + 3 ] = cb.x;\n\t\t\t\t\tnormals[ i + 4 ] = cb.y;\n\t\t\t\t\tnormals[ i + 5 ] = cb.z;\n\n\t\t\t\t\tnormals[ i + 6 ] = cb.x;\n\t\t\t\t\tnormals[ i + 7 ] = cb.y;\n\t\t\t\t\tnormals[ i + 8 ] = cb.z;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.normalizeNormals();\n\n\t\t\tattributes.normal.needsUpdate = true;\n\n\t\t}\n\n\t},\n\n\tmerge: function ( geometry, offset ) {\n\n\t\tif ( ( geometry && geometry.isBufferGeometry ) === false ) {\n\n\t\t\tconsole.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tvar attributes = this.attributes;\n\n\t\tfor ( var key in attributes ) {\n\n\t\t\tif ( geometry.attributes[ key ] === undefined ) continue;\n\n\t\t\tvar attribute1 = attributes[ key ];\n\t\t\tvar attributeArray1 = attribute1.array;\n\n\t\t\tvar attribute2 = geometry.attributes[ key ];\n\t\t\tvar attributeArray2 = attribute2.array;\n\n\t\t\tvar attributeSize = attribute2.itemSize;\n\n\t\t\tfor ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) {\n\n\t\t\t\tattributeArray1[ j ] = attributeArray2[ i ];\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tnormalizeNormals: function () {\n\n\t\tvar normals = this.attributes.normal.array;\n\n\t\tvar x, y, z, n;\n\n\t\tfor ( var i = 0, il = normals.length; i < il; i += 3 ) {\n\n\t\t\tx = normals[ i ];\n\t\t\ty = normals[ i + 1 ];\n\t\t\tz = normals[ i + 2 ];\n\n\t\t\tn = 1.0 / Math.sqrt( x * x + y * y + z * z );\n\n\t\t\tnormals[ i ] *= n;\n\t\t\tnormals[ i + 1 ] *= n;\n\t\t\tnormals[ i + 2 ] *= n;\n\n\t\t}\n\n\t},\n\n\ttoNonIndexed: function () {\n\n\t\tif ( this.index === null ) {\n\n\t\t\tconsole.warn( 'THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.' );\n\t\t\treturn this;\n\n\t\t}\n\n\t\tvar geometry2 = new BufferGeometry();\n\n\t\tvar indices = this.index.array;\n\t\tvar attributes = this.attributes;\n\n\t\tfor ( var name in attributes ) {\n\n\t\t\tvar attribute = attributes[ name ];\n\n\t\t\tvar array = attribute.array;\n\t\t\tvar itemSize = attribute.itemSize;\n\n\t\t\tvar array2 = new array.constructor( indices.length * itemSize );\n\n\t\t\tvar index = 0, index2 = 0;\n\n\t\t\tfor ( var i = 0, l = indices.length; i < l; i ++ ) {\n\n\t\t\t\tindex = indices[ i ] * itemSize;\n\n\t\t\t\tfor ( var j = 0; j < itemSize; j ++ ) {\n\n\t\t\t\t\tarray2[ index2 ++ ] = array[ index ++ ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tgeometry2.addAttribute( name, new BufferAttribute( array2, itemSize ) );\n\n\t\t}\n\n\t\treturn geometry2;\n\n\t},\n\n\ttoJSON: function () {\n\n\t\tvar data = {\n\t\t\tmetadata: {\n\t\t\t\tversion: 4.4,\n\t\t\t\ttype: 'BufferGeometry',\n\t\t\t\tgenerator: 'BufferGeometry.toJSON'\n\t\t\t}\n\t\t};\n\n\t\t// standard BufferGeometry serialization\n\n\t\tdata.uuid = this.uuid;\n\t\tdata.type = this.type;\n\t\tif ( this.name !== '' ) data.name = this.name;\n\n\t\tif ( this.parameters !== undefined ) {\n\n\t\t\tvar parameters = this.parameters;\n\n\t\t\tfor ( var key in parameters ) {\n\n\t\t\t\tif ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tdata.data = { attributes: {} };\n\n\t\tvar index = this.index;\n\n\t\tif ( index !== null ) {\n\n\t\t\tvar array = Array.prototype.slice.call( index.array );\n\n\t\t\tdata.data.index = {\n\t\t\t\ttype: index.array.constructor.name,\n\t\t\t\tarray: array\n\t\t\t};\n\n\t\t}\n\n\t\tvar attributes = this.attributes;\n\n\t\tfor ( var key in attributes ) {\n\n\t\t\tvar attribute = attributes[ key ];\n\n\t\t\tvar array = Array.prototype.slice.call( attribute.array );\n\n\t\t\tdata.data.attributes[ key ] = {\n\t\t\t\titemSize: attribute.itemSize,\n\t\t\t\ttype: attribute.array.constructor.name,\n\t\t\t\tarray: array,\n\t\t\t\tnormalized: attribute.normalized\n\t\t\t};\n\n\t\t}\n\n\t\tvar groups = this.groups;\n\n\t\tif ( groups.length > 0 ) {\n\n\t\t\tdata.data.groups = JSON.parse( JSON.stringify( groups ) );\n\n\t\t}\n\n\t\tvar boundingSphere = this.boundingSphere;\n\n\t\tif ( boundingSphere !== null ) {\n\n\t\t\tdata.data.boundingSphere = {\n\t\t\t\tcenter: boundingSphere.center.toArray(),\n\t\t\t\tradius: boundingSphere.radius\n\t\t\t};\n\n\t\t}\n\n\t\treturn data;\n\n\t},\n\n\tclone: function () {\n\n\t\t/*\n\t\t// Handle primitives\n\n\t\tvar parameters = this.parameters;\n\n\t\tif ( parameters !== undefined ) {\n\n\t\t\tvar values = [];\n\n\t\t\tfor ( var key in parameters ) {\n\n\t\t\t\tvalues.push( parameters[ key ] );\n\n\t\t\t}\n\n\t\t\tvar geometry = Object.create( this.constructor.prototype );\n\t\t\tthis.constructor.apply( geometry, values );\n\t\t\treturn geometry;\n\n\t\t}\n\n\t\treturn new this.constructor().copy( this );\n\t\t*/\n\n\t\treturn new BufferGeometry().copy( this );\n\n\t},\n\n\tcopy: function ( source ) {\n\n\t\tvar name, i, l;\n\n\t\t// reset\n\n\t\tthis.index = null;\n\t\tthis.attributes = {};\n\t\tthis.morphAttributes = {};\n\t\tthis.groups = [];\n\t\tthis.boundingBox = null;\n\t\tthis.boundingSphere = null;\n\n\t\t// name\n\n\t\tthis.name = source.name;\n\n\t\t// index\n\n\t\tvar index = source.index;\n\n\t\tif ( index !== null ) {\n\n\t\t\tthis.setIndex( index.clone() );\n\n\t\t}\n\n\t\t// attributes\n\n\t\tvar attributes = source.attributes;\n\n\t\tfor ( name in attributes ) {\n\n\t\t\tvar attribute = attributes[ name ];\n\t\t\tthis.addAttribute( name, attribute.clone() );\n\n\t\t}\n\n\t\t// morph attributes\n\n\t\tvar morphAttributes = source.morphAttributes;\n\n\t\tfor ( name in morphAttributes ) {\n\n\t\t\tvar array = [];\n\t\t\tvar morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes\n\n\t\t\tfor ( i = 0, l = morphAttribute.length; i < l; i ++ ) {\n\n\t\t\t\tarray.push( morphAttribute[ i ].clone() );\n\n\t\t\t}\n\n\t\t\tthis.morphAttributes[ name ] = array;\n\n\t\t}\n\n\t\t// groups\n\n\t\tvar groups = source.groups;\n\n\t\tfor ( i = 0, l = groups.length; i < l; i ++ ) {\n\n\t\t\tvar group = groups[ i ];\n\t\t\tthis.addGroup( group.start, group.count, group.materialIndex );\n\n\t\t}\n\n\t\t// bounding box\n\n\t\tvar boundingBox = source.boundingBox;\n\n\t\tif ( boundingBox !== null ) {\n\n\t\t\tthis.boundingBox = boundingBox.clone();\n\n\t\t}\n\n\t\t// bounding sphere\n\n\t\tvar boundingSphere = source.boundingSphere;\n\n\t\tif ( boundingSphere !== null ) {\n\n\t\t\tthis.boundingSphere = boundingSphere.clone();\n\n\t\t}\n\n\t\t// draw range\n\n\t\tthis.drawRange.start = source.drawRange.start;\n\t\tthis.drawRange.count = source.drawRange.count;\n\n\t\treturn this;\n\n\t},\n\n\tdispose: function () {\n\n\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t}\n\n};\n\nBufferGeometry.MaxIndex = 65535;\n\nObject.assign( BufferGeometry.prototype, EventDispatcher.prototype );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author alteredq / http://alteredqualia.com/\n * @author mikael emtinger / http://gomo.se/\n * @author jonobr1 / http://jonobr1.com/\n */\n\nfunction Mesh( geometry, material ) {\n\n\tObject3D.call( this );\n\n\tthis.type = 'Mesh';\n\n\tthis.geometry = geometry !== undefined ? geometry : new BufferGeometry();\n\tthis.material = material !== undefined ? material : new MeshBasicMaterial( { color: Math.random() * 0xffffff } );\n\n\tthis.drawMode = TrianglesDrawMode;\n\n\tthis.updateMorphTargets();\n\n}\n\nMesh.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\tconstructor: Mesh,\n\n\tisMesh: true,\n\n\tsetDrawMode: function ( value ) {\n\n\t\tthis.drawMode = value;\n\n\t},\n\n\tcopy: function ( source ) {\n\n\t\tObject3D.prototype.copy.call( this, source );\n\n\t\tthis.drawMode = source.drawMode;\n\n\t\treturn this;\n\n\t},\n\n\tupdateMorphTargets: function () {\n\n\t\tvar morphTargets = this.geometry.morphTargets;\n\n\t\tif ( morphTargets !== undefined && morphTargets.length > 0 ) {\n\n\t\t\tthis.morphTargetInfluences = [];\n\t\t\tthis.morphTargetDictionary = {};\n\n\t\t\tfor ( var m = 0, ml = morphTargets.length; m < ml; m ++ ) {\n\n\t\t\t\tthis.morphTargetInfluences.push( 0 );\n\t\t\t\tthis.morphTargetDictionary[ morphTargets[ m ].name ] = m;\n\n\t\t\t}\n\n\t\t}\n\n\t},\n\n\traycast: ( function () {\n\n\t\tvar inverseMatrix = new Matrix4();\n\t\tvar ray = new Ray();\n\t\tvar sphere = new Sphere();\n\n\t\tvar vA = new Vector3();\n\t\tvar vB = new Vector3();\n\t\tvar vC = new Vector3();\n\n\t\tvar tempA = new Vector3();\n\t\tvar tempB = new Vector3();\n\t\tvar tempC = new Vector3();\n\n\t\tvar uvA = new Vector2();\n\t\tvar uvB = new Vector2();\n\t\tvar uvC = new Vector2();\n\n\t\tvar barycoord = new Vector3();\n\n\t\tvar intersectionPoint = new Vector3();\n\t\tvar intersectionPointWorld = new Vector3();\n\n\t\tfunction uvIntersection( point, p1, p2, p3, uv1, uv2, uv3 ) {\n\n\t\t\tTriangle.barycoordFromPoint( point, p1, p2, p3, barycoord );\n\n\t\t\tuv1.multiplyScalar( barycoord.x );\n\t\t\tuv2.multiplyScalar( barycoord.y );\n\t\t\tuv3.multiplyScalar( barycoord.z );\n\n\t\t\tuv1.add( uv2 ).add( uv3 );\n\n\t\t\treturn uv1.clone();\n\n\t\t}\n\n\t\tfunction checkIntersection( object, raycaster, ray, pA, pB, pC, point ) {\n\n\t\t\tvar intersect;\n\t\t\tvar material = object.material;\n\n\t\t\tif ( material.side === BackSide ) {\n\n\t\t\t\tintersect = ray.intersectTriangle( pC, pB, pA, true, point );\n\n\t\t\t} else {\n\n\t\t\t\tintersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point );\n\n\t\t\t}\n\n\t\t\tif ( intersect === null ) return null;\n\n\t\t\tintersectionPointWorld.copy( point );\n\t\t\tintersectionPointWorld.applyMatrix4( object.matrixWorld );\n\n\t\t\tvar distance = raycaster.ray.origin.distanceTo( intersectionPointWorld );\n\n\t\t\tif ( distance < raycaster.near || distance > raycaster.far ) return null;\n\n\t\t\treturn {\n\t\t\t\tdistance: distance,\n\t\t\t\tpoint: intersectionPointWorld.clone(),\n\t\t\t\tobject: object\n\t\t\t};\n\n\t\t}\n\n\t\tfunction checkBufferGeometryIntersection( object, raycaster, ray, position, uv, a, b, c ) {\n\n\t\t\tvA.fromBufferAttribute( position, a );\n\t\t\tvB.fromBufferAttribute( position, b );\n\t\t\tvC.fromBufferAttribute( position, c );\n\n\t\t\tvar intersection = checkIntersection( object, raycaster, ray, vA, vB, vC, intersectionPoint );\n\n\t\t\tif ( intersection ) {\n\n\t\t\t\tif ( uv ) {\n\n\t\t\t\t\tuvA.fromBufferAttribute( uv, a );\n\t\t\t\t\tuvB.fromBufferAttribute( uv, b );\n\t\t\t\t\tuvC.fromBufferAttribute( uv, c );\n\n\t\t\t\t\tintersection.uv = uvIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC );\n\n\t\t\t\t}\n\n\t\t\t\tintersection.face = new Face3( a, b, c, Triangle.normal( vA, vB, vC ) );\n\t\t\t\tintersection.faceIndex = a;\n\n\t\t\t}\n\n\t\t\treturn intersection;\n\n\t\t}\n\n\t\treturn function raycast( raycaster, intersects ) {\n\n\t\t\tvar geometry = this.geometry;\n\t\t\tvar material = this.material;\n\t\t\tvar matrixWorld = this.matrixWorld;\n\n\t\t\tif ( material === undefined ) return;\n\n\t\t\t// Checking boundingSphere distance to ray\n\n\t\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\n\n\t\t\tsphere.copy( geometry.boundingSphere );\n\t\t\tsphere.applyMatrix4( matrixWorld );\n\n\t\t\tif ( raycaster.ray.intersectsSphere( sphere ) === false ) return;\n\n\t\t\t//\n\n\t\t\tinverseMatrix.getInverse( matrixWorld );\n\t\t\tray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );\n\n\t\t\t// Check boundingBox before continuing\n\n\t\t\tif ( geometry.boundingBox !== null ) {\n\n\t\t\t\tif ( ray.intersectsBox( geometry.boundingBox ) === false ) return;\n\n\t\t\t}\n\n\t\t\tvar intersection;\n\n\t\t\tif ( geometry.isBufferGeometry ) {\n\n\t\t\t\tvar a, b, c;\n\t\t\t\tvar index = geometry.index;\n\t\t\t\tvar position = geometry.attributes.position;\n\t\t\t\tvar uv = geometry.attributes.uv;\n\t\t\t\tvar i, l;\n\n\t\t\t\tif ( index !== null ) {\n\n\t\t\t\t\t// indexed buffer geometry\n\n\t\t\t\t\tfor ( i = 0, l = index.count; i < l; i += 3 ) {\n\n\t\t\t\t\t\ta = index.getX( i );\n\t\t\t\t\t\tb = index.getX( i + 1 );\n\t\t\t\t\t\tc = index.getX( i + 2 );\n\n\t\t\t\t\t\tintersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c );\n\n\t\t\t\t\t\tif ( intersection ) {\n\n\t\t\t\t\t\t\tintersection.faceIndex = Math.floor( i / 3 ); // triangle number in indices buffer semantics\n\t\t\t\t\t\t\tintersects.push( intersection );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// non-indexed buffer geometry\n\n\t\t\t\t\tfor ( i = 0, l = position.count; i < l; i += 3 ) {\n\n\t\t\t\t\t\ta = i;\n\t\t\t\t\t\tb = i + 1;\n\t\t\t\t\t\tc = i + 2;\n\n\t\t\t\t\t\tintersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c );\n\n\t\t\t\t\t\tif ( intersection ) {\n\n\t\t\t\t\t\t\tintersection.index = a; // triangle number in positions buffer semantics\n\t\t\t\t\t\t\tintersects.push( intersection );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else if ( geometry.isGeometry ) {\n\n\t\t\t\tvar fvA, fvB, fvC;\n\t\t\t\tvar isFaceMaterial = ( material && material.isMultiMaterial );\n\t\t\t\tvar materials = isFaceMaterial === true ? material.materials : null;\n\n\t\t\t\tvar vertices = geometry.vertices;\n\t\t\t\tvar faces = geometry.faces;\n\t\t\t\tvar uvs;\n\n\t\t\t\tvar faceVertexUvs = geometry.faceVertexUvs[ 0 ];\n\t\t\t\tif ( faceVertexUvs.length > 0 ) uvs = faceVertexUvs;\n\n\t\t\t\tfor ( var f = 0, fl = faces.length; f < fl; f ++ ) {\n\n\t\t\t\t\tvar face = faces[ f ];\n\t\t\t\t\tvar faceMaterial = isFaceMaterial === true ? materials[ face.materialIndex ] : material;\n\n\t\t\t\t\tif ( faceMaterial === undefined ) continue;\n\n\t\t\t\t\tfvA = vertices[ face.a ];\n\t\t\t\t\tfvB = vertices[ face.b ];\n\t\t\t\t\tfvC = vertices[ face.c ];\n\n\t\t\t\t\tif ( faceMaterial.morphTargets === true ) {\n\n\t\t\t\t\t\tvar morphTargets = geometry.morphTargets;\n\t\t\t\t\t\tvar morphInfluences = this.morphTargetInfluences;\n\n\t\t\t\t\t\tvA.set( 0, 0, 0 );\n\t\t\t\t\t\tvB.set( 0, 0, 0 );\n\t\t\t\t\t\tvC.set( 0, 0, 0 );\n\n\t\t\t\t\t\tfor ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {\n\n\t\t\t\t\t\t\tvar influence = morphInfluences[ t ];\n\n\t\t\t\t\t\t\tif ( influence === 0 ) continue;\n\n\t\t\t\t\t\t\tvar targets = morphTargets[ t ].vertices;\n\n\t\t\t\t\t\t\tvA.addScaledVector( tempA.subVectors( targets[ face.a ], fvA ), influence );\n\t\t\t\t\t\t\tvB.addScaledVector( tempB.subVectors( targets[ face.b ], fvB ), influence );\n\t\t\t\t\t\t\tvC.addScaledVector( tempC.subVectors( targets[ face.c ], fvC ), influence );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvA.add( fvA );\n\t\t\t\t\t\tvB.add( fvB );\n\t\t\t\t\t\tvC.add( fvC );\n\n\t\t\t\t\t\tfvA = vA;\n\t\t\t\t\t\tfvB = vB;\n\t\t\t\t\t\tfvC = vC;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tintersection = checkIntersection( this, raycaster, ray, fvA, fvB, fvC, intersectionPoint );\n\n\t\t\t\t\tif ( intersection ) {\n\n\t\t\t\t\t\tif ( uvs ) {\n\n\t\t\t\t\t\t\tvar uvs_f = uvs[ f ];\n\t\t\t\t\t\t\tuvA.copy( uvs_f[ 0 ] );\n\t\t\t\t\t\t\tuvB.copy( uvs_f[ 1 ] );\n\t\t\t\t\t\t\tuvC.copy( uvs_f[ 2 ] );\n\n\t\t\t\t\t\t\tintersection.uv = uvIntersection( intersectionPoint, fvA, fvB, fvC, uvA, uvB, uvC );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tintersection.face = face;\n\t\t\t\t\t\tintersection.faceIndex = f;\n\t\t\t\t\t\tintersects.push( intersection );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t}() ),\n\n\tclone: function () {\n\n\t\treturn new this.constructor( this.geometry, this.material ).copy( this );\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as\n */\n\nfunction BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) {\n\n\tGeometry.call( this );\n\n\tthis.type = 'BoxGeometry';\n\n\tthis.parameters = {\n\t\twidth: width,\n\t\theight: height,\n\t\tdepth: depth,\n\t\twidthSegments: widthSegments,\n\t\theightSegments: heightSegments,\n\t\tdepthSegments: depthSegments\n\t};\n\n\tthis.fromBufferGeometry( new BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) );\n\tthis.mergeVertices();\n\n}\n\nBoxGeometry.prototype = Object.create( Geometry.prototype );\nBoxGeometry.prototype.constructor = BoxGeometry;\n\n/**\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) {\n\n\tBufferGeometry.call( this );\n\n\tthis.type = 'BoxBufferGeometry';\n\n\tthis.parameters = {\n\t\twidth: width,\n\t\theight: height,\n\t\tdepth: depth,\n\t\twidthSegments: widthSegments,\n\t\theightSegments: heightSegments,\n\t\tdepthSegments: depthSegments\n\t};\n\n\tvar scope = this;\n\n\t// segments\n\n\twidthSegments = Math.floor( widthSegments ) || 1;\n\theightSegments = Math.floor( heightSegments ) || 1;\n\tdepthSegments = Math.floor( depthSegments ) || 1;\n\n\t// buffers\n\n\tvar indices = [];\n\tvar vertices = [];\n\tvar normals = [];\n\tvar uvs = [];\n\n\t// helper variables\n\n\tvar numberOfVertices = 0;\n\tvar groupStart = 0;\n\n\t// build each side of the box geometry\n\n\tbuildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px\n\tbuildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx\n\tbuildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py\n\tbuildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny\n\tbuildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz\n\tbuildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz\n\n\t// build geometry\n\n\tthis.setIndex( indices );\n\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\tfunction buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {\n\n\t\tvar segmentWidth = width / gridX;\n\t\tvar segmentHeight = height / gridY;\n\n\t\tvar widthHalf = width / 2;\n\t\tvar heightHalf = height / 2;\n\t\tvar depthHalf = depth / 2;\n\n\t\tvar gridX1 = gridX + 1;\n\t\tvar gridY1 = gridY + 1;\n\n\t\tvar vertexCounter = 0;\n\t\tvar groupCount = 0;\n\n\t\tvar ix, iy;\n\n\t\tvar vector = new Vector3();\n\n\t\t// generate vertices, normals and uvs\n\n\t\tfor ( iy = 0; iy < gridY1; iy ++ ) {\n\n\t\t\tvar y = iy * segmentHeight - heightHalf;\n\n\t\t\tfor ( ix = 0; ix < gridX1; ix ++ ) {\n\n\t\t\t\tvar x = ix * segmentWidth - widthHalf;\n\n\t\t\t\t// set values to correct vector component\n\n\t\t\t\tvector[ u ] = x * udir;\n\t\t\t\tvector[ v ] = y * vdir;\n\t\t\t\tvector[ w ] = depthHalf;\n\n\t\t\t\t// now apply vector to vertex buffer\n\n\t\t\t\tvertices.push( vector.x, vector.y, vector.z );\n\n\t\t\t\t// set values to correct vector component\n\n\t\t\t\tvector[ u ] = 0;\n\t\t\t\tvector[ v ] = 0;\n\t\t\t\tvector[ w ] = depth > 0 ? 1 : - 1;\n\n\t\t\t\t// now apply vector to normal buffer\n\n\t\t\t\tnormals.push( vector.x, vector.y, vector.z );\n\n\t\t\t\t// uvs\n\n\t\t\t\tuvs.push( ix / gridX );\n\t\t\t\tuvs.push( 1 - ( iy / gridY ) );\n\n\t\t\t\t// counters\n\n\t\t\t\tvertexCounter += 1;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// indices\n\n\t\t// 1. you need three indices to draw a single face\n\t\t// 2. a single segment consists of two faces\n\t\t// 3. so we need to generate six (2*3) indices per segment\n\n\t\tfor ( iy = 0; iy < gridY; iy ++ ) {\n\n\t\t\tfor ( ix = 0; ix < gridX; ix ++ ) {\n\n\t\t\t\tvar a = numberOfVertices + ix + gridX1 * iy;\n\t\t\t\tvar b = numberOfVertices + ix + gridX1 * ( iy + 1 );\n\t\t\t\tvar c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );\n\t\t\t\tvar d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;\n\n\t\t\t\t// faces\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( b, c, d );\n\n\t\t\t\t// increase counter\n\n\t\t\t\tgroupCount += 6;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// add a group to the geometry. this will ensure multi material support\n\n\t\tscope.addGroup( groupStart, groupCount, materialIndex );\n\n\t\t// calculate new start value for groups\n\n\t\tgroupStart += groupCount;\n\n\t\t// update total number of vertices\n\n\t\tnumberOfVertices += vertexCounter;\n\n\t}\n\n}\n\nBoxBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\nBoxBufferGeometry.prototype.constructor = BoxBufferGeometry;\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as\n */\n\nfunction PlaneGeometry( width, height, widthSegments, heightSegments ) {\n\n\tGeometry.call( this );\n\n\tthis.type = 'PlaneGeometry';\n\n\tthis.parameters = {\n\t\twidth: width,\n\t\theight: height,\n\t\twidthSegments: widthSegments,\n\t\theightSegments: heightSegments\n\t};\n\n\tthis.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) );\n\n}\n\nPlaneGeometry.prototype = Object.create( Geometry.prototype );\nPlaneGeometry.prototype.constructor = PlaneGeometry;\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author Mugen87 / https://github.com/Mugen87\n *\n * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as\n */\n\nfunction PlaneBufferGeometry( width, height, widthSegments, heightSegments ) {\n\n\tBufferGeometry.call( this );\n\n\tthis.type = 'PlaneBufferGeometry';\n\n\tthis.parameters = {\n\t\twidth: width,\n\t\theight: height,\n\t\twidthSegments: widthSegments,\n\t\theightSegments: heightSegments\n\t};\n\n\tvar width_half = width / 2;\n\tvar height_half = height / 2;\n\n\tvar gridX = Math.floor( widthSegments ) || 1;\n\tvar gridY = Math.floor( heightSegments ) || 1;\n\n\tvar gridX1 = gridX + 1;\n\tvar gridY1 = gridY + 1;\n\n\tvar segment_width = width / gridX;\n\tvar segment_height = height / gridY;\n\n\tvar ix, iy;\n\n\t// buffers\n\n\tvar indices = [];\n\tvar vertices = [];\n\tvar normals = [];\n\tvar uvs = [];\n\n\t// generate vertices, normals and uvs\n\n\tfor ( iy = 0; iy < gridY1; iy ++ ) {\n\n\t\tvar y = iy * segment_height - height_half;\n\n\t\tfor ( ix = 0; ix < gridX1; ix ++ ) {\n\n\t\t\tvar x = ix * segment_width - width_half;\n\n\t\t\tvertices.push( x, - y, 0 );\n\n\t\t\tnormals.push( 0, 0, 1 );\n\n\t\t\tuvs.push( ix / gridX );\n\t\t\tuvs.push( 1 - ( iy / gridY ) );\n\n\t\t}\n\n\t}\n\n\t// indices\n\n\tfor ( iy = 0; iy < gridY; iy ++ ) {\n\n\t\tfor ( ix = 0; ix < gridX; ix ++ ) {\n\n\t\t\tvar a = ix + gridX1 * iy;\n\t\t\tvar b = ix + gridX1 * ( iy + 1 );\n\t\t\tvar c = ( ix + 1 ) + gridX1 * ( iy + 1 );\n\t\t\tvar d = ( ix + 1 ) + gridX1 * iy;\n\n\t\t\t// faces\n\n\t\t\tindices.push( a, b, d );\n\t\t\tindices.push( b, c, d );\n\n\t\t}\n\n\t}\n\n\t// build geometry\n\n\tthis.setIndex( indices );\n\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n}\n\nPlaneBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\nPlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry;\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author mikael emtinger / http://gomo.se/\n * @author WestLangley / http://github.com/WestLangley\n*/\n\nfunction Camera() {\n\n\tObject3D.call( this );\n\n\tthis.type = 'Camera';\n\n\tthis.matrixWorldInverse = new Matrix4();\n\tthis.projectionMatrix = new Matrix4();\n\n}\n\nCamera.prototype = Object.create( Object3D.prototype );\nCamera.prototype.constructor = Camera;\n\nCamera.prototype.isCamera = true;\n\nCamera.prototype.getWorldDirection = function () {\n\n\tvar quaternion = new Quaternion();\n\n\treturn function getWorldDirection( optionalTarget ) {\n\n\t\tvar result = optionalTarget || new Vector3();\n\n\t\tthis.getWorldQuaternion( quaternion );\n\n\t\treturn result.set( 0, 0, - 1 ).applyQuaternion( quaternion );\n\n\t};\n\n}();\n\nCamera.prototype.lookAt = function () {\n\n\t// This routine does not support cameras with rotated and/or translated parent(s)\n\n\tvar m1 = new Matrix4();\n\n\treturn function lookAt( vector ) {\n\n\t\tm1.lookAt( this.position, vector, this.up );\n\n\t\tthis.quaternion.setFromRotationMatrix( m1 );\n\n\t};\n\n}();\n\nCamera.prototype.clone = function () {\n\n\treturn new this.constructor().copy( this );\n\n};\n\nCamera.prototype.copy = function ( source ) {\n\n\tObject3D.prototype.copy.call( this, source );\n\n\tthis.matrixWorldInverse.copy( source.matrixWorldInverse );\n\tthis.projectionMatrix.copy( source.projectionMatrix );\n\n\treturn this;\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author greggman / http://games.greggman.com/\n * @author zz85 / http://www.lab4games.net/zz85/blog\n * @author tschw\n */\n\nfunction PerspectiveCamera( fov, aspect, near, far ) {\n\n\tCamera.call( this );\n\n\tthis.type = 'PerspectiveCamera';\n\n\tthis.fov = fov !== undefined ? fov : 50;\n\tthis.zoom = 1;\n\n\tthis.near = near !== undefined ? near : 0.1;\n\tthis.far = far !== undefined ? far : 2000;\n\tthis.focus = 10;\n\n\tthis.aspect = aspect !== undefined ? aspect : 1;\n\tthis.view = null;\n\n\tthis.filmGauge = 35;\t// width of the film (default in millimeters)\n\tthis.filmOffset = 0;\t// horizontal film offset (same unit as gauge)\n\n\tthis.updateProjectionMatrix();\n\n}\n\nPerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ), {\n\n\tconstructor: PerspectiveCamera,\n\n\tisPerspectiveCamera: true,\n\n\tcopy: function ( source ) {\n\n\t\tCamera.prototype.copy.call( this, source );\n\n\t\tthis.fov = source.fov;\n\t\tthis.zoom = source.zoom;\n\n\t\tthis.near = source.near;\n\t\tthis.far = source.far;\n\t\tthis.focus = source.focus;\n\n\t\tthis.aspect = source.aspect;\n\t\tthis.view = source.view === null ? null : Object.assign( {}, source.view );\n\n\t\tthis.filmGauge = source.filmGauge;\n\t\tthis.filmOffset = source.filmOffset;\n\n\t\treturn this;\n\n\t},\n\n\t/**\n\t * Sets the FOV by focal length in respect to the current .filmGauge.\n\t *\n\t * The default film gauge is 35, so that the focal length can be specified for\n\t * a 35mm (full frame) camera.\n\t *\n\t * Values for focal length and film gauge must have the same unit.\n\t */\n\tsetFocalLength: function ( focalLength ) {\n\n\t\t// see http://www.bobatkins.com/photography/technical/field_of_view.html\n\t\tvar vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;\n\n\t\tthis.fov = _Math.RAD2DEG * 2 * Math.atan( vExtentSlope );\n\t\tthis.updateProjectionMatrix();\n\n\t},\n\n\t/**\n\t * Calculates the focal length from the current .fov and .filmGauge.\n\t */\n\tgetFocalLength: function () {\n\n\t\tvar vExtentSlope = Math.tan( _Math.DEG2RAD * 0.5 * this.fov );\n\n\t\treturn 0.5 * this.getFilmHeight() / vExtentSlope;\n\n\t},\n\n\tgetEffectiveFOV: function () {\n\n\t\treturn _Math.RAD2DEG * 2 * Math.atan(\n\t\t\t\tMath.tan( _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom );\n\n\t},\n\n\tgetFilmWidth: function () {\n\n\t\t// film not completely covered in portrait format (aspect < 1)\n\t\treturn this.filmGauge * Math.min( this.aspect, 1 );\n\n\t},\n\n\tgetFilmHeight: function () {\n\n\t\t// film not completely covered in landscape format (aspect > 1)\n\t\treturn this.filmGauge / Math.max( this.aspect, 1 );\n\n\t},\n\n\t/**\n\t * Sets an offset in a larger frustum. This is useful for multi-window or\n\t * multi-monitor/multi-machine setups.\n\t *\n\t * For example, if you have 3x2 monitors and each monitor is 1920x1080 and\n\t * the monitors are in grid like this\n\t *\n\t * +---+---+---+\n\t * | A | B | C |\n\t * +---+---+---+\n\t * | D | E | F |\n\t * +---+---+---+\n\t *\n\t * then for each monitor you would call it like this\n\t *\n\t * var w = 1920;\n\t * var h = 1080;\n\t * var fullWidth = w * 3;\n\t * var fullHeight = h * 2;\n\t *\n\t * --A--\n\t * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );\n\t * --B--\n\t * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );\n\t * --C--\n\t * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );\n\t * --D--\n\t * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );\n\t * --E--\n\t * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );\n\t * --F--\n\t * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );\n\t *\n\t * Note there is no reason monitors have to be the same size or in a grid.\n\t */\n\tsetViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) {\n\n\t\tthis.aspect = fullWidth / fullHeight;\n\n\t\tthis.view = {\n\t\t\tfullWidth: fullWidth,\n\t\t\tfullHeight: fullHeight,\n\t\t\toffsetX: x,\n\t\t\toffsetY: y,\n\t\t\twidth: width,\n\t\t\theight: height\n\t\t};\n\n\t\tthis.updateProjectionMatrix();\n\n\t},\n\n\tclearViewOffset: function() {\n\n\t\tthis.view = null;\n\t\tthis.updateProjectionMatrix();\n\n\t},\n\n\tupdateProjectionMatrix: function () {\n\n\t\tvar near = this.near,\n\t\t\ttop = near * Math.tan(\n\t\t\t\t\t_Math.DEG2RAD * 0.5 * this.fov ) / this.zoom,\n\t\t\theight = 2 * top,\n\t\t\twidth = this.aspect * height,\n\t\t\tleft = - 0.5 * width,\n\t\t\tview = this.view;\n\n\t\tif ( view !== null ) {\n\n\t\t\tvar fullWidth = view.fullWidth,\n\t\t\t\tfullHeight = view.fullHeight;\n\n\t\t\tleft += view.offsetX * width / fullWidth;\n\t\t\ttop -= view.offsetY * height / fullHeight;\n\t\t\twidth *= view.width / fullWidth;\n\t\t\theight *= view.height / fullHeight;\n\n\t\t}\n\n\t\tvar skew = this.filmOffset;\n\t\tif ( skew !== 0 ) left += near * skew / this.getFilmWidth();\n\n\t\tthis.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far );\n\n\t},\n\n\ttoJSON: function ( meta ) {\n\n\t\tvar data = Object3D.prototype.toJSON.call( this, meta );\n\n\t\tdata.object.fov = this.fov;\n\t\tdata.object.zoom = this.zoom;\n\n\t\tdata.object.near = this.near;\n\t\tdata.object.far = this.far;\n\t\tdata.object.focus = this.focus;\n\n\t\tdata.object.aspect = this.aspect;\n\n\t\tif ( this.view !== null ) data.object.view = Object.assign( {}, this.view );\n\n\t\tdata.object.filmGauge = this.filmGauge;\n\t\tdata.object.filmOffset = this.filmOffset;\n\n\t\treturn data;\n\n\t}\n\n} );\n\n/**\n * @author alteredq / http://alteredqualia.com/\n * @author arose / http://github.com/arose\n */\n\nfunction OrthographicCamera( left, right, top, bottom, near, far ) {\n\n\tCamera.call( this );\n\n\tthis.type = 'OrthographicCamera';\n\n\tthis.zoom = 1;\n\tthis.view = null;\n\n\tthis.left = left;\n\tthis.right = right;\n\tthis.top = top;\n\tthis.bottom = bottom;\n\n\tthis.near = ( near !== undefined ) ? near : 0.1;\n\tthis.far = ( far !== undefined ) ? far : 2000;\n\n\tthis.updateProjectionMatrix();\n\n}\n\nOrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), {\n\n\tconstructor: OrthographicCamera,\n\n\tisOrthographicCamera: true,\n\n\tcopy: function ( source ) {\n\n\t\tCamera.prototype.copy.call( this, source );\n\n\t\tthis.left = source.left;\n\t\tthis.right = source.right;\n\t\tthis.top = source.top;\n\t\tthis.bottom = source.bottom;\n\t\tthis.near = source.near;\n\t\tthis.far = source.far;\n\n\t\tthis.zoom = source.zoom;\n\t\tthis.view = source.view === null ? null : Object.assign( {}, source.view );\n\n\t\treturn this;\n\n\t},\n\n\tsetViewOffset: function( fullWidth, fullHeight, x, y, width, height ) {\n\n\t\tthis.view = {\n\t\t\tfullWidth: fullWidth,\n\t\t\tfullHeight: fullHeight,\n\t\t\toffsetX: x,\n\t\t\toffsetY: y,\n\t\t\twidth: width,\n\t\t\theight: height\n\t\t};\n\n\t\tthis.updateProjectionMatrix();\n\n\t},\n\n\tclearViewOffset: function() {\n\n\t\tthis.view = null;\n\t\tthis.updateProjectionMatrix();\n\n\t},\n\n\tupdateProjectionMatrix: function () {\n\n\t\tvar dx = ( this.right - this.left ) / ( 2 * this.zoom );\n\t\tvar dy = ( this.top - this.bottom ) / ( 2 * this.zoom );\n\t\tvar cx = ( this.right + this.left ) / 2;\n\t\tvar cy = ( this.top + this.bottom ) / 2;\n\n\t\tvar left = cx - dx;\n\t\tvar right = cx + dx;\n\t\tvar top = cy + dy;\n\t\tvar bottom = cy - dy;\n\n\t\tif ( this.view !== null ) {\n\n\t\t\tvar zoomW = this.zoom / ( this.view.width / this.view.fullWidth );\n\t\t\tvar zoomH = this.zoom / ( this.view.height / this.view.fullHeight );\n\t\t\tvar scaleW = ( this.right - this.left ) / this.view.width;\n\t\t\tvar scaleH = ( this.top - this.bottom ) / this.view.height;\n\n\t\t\tleft += scaleW * ( this.view.offsetX / zoomW );\n\t\t\tright = left + scaleW * ( this.view.width / zoomW );\n\t\t\ttop -= scaleH * ( this.view.offsetY / zoomH );\n\t\t\tbottom = top - scaleH * ( this.view.height / zoomH );\n\n\t\t}\n\n\t\tthis.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far );\n\n\t},\n\n\ttoJSON: function ( meta ) {\n\n\t\tvar data = Object3D.prototype.toJSON.call( this, meta );\n\n\t\tdata.object.zoom = this.zoom;\n\t\tdata.object.left = this.left;\n\t\tdata.object.right = this.right;\n\t\tdata.object.top = this.top;\n\t\tdata.object.bottom = this.bottom;\n\t\tdata.object.near = this.near;\n\t\tdata.object.far = this.far;\n\n\t\tif ( this.view !== null ) data.object.view = Object.assign( {}, this.view );\n\n\t\treturn data;\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction WebGLIndexedBufferRenderer( gl, extensions, infoRender ) {\n\n\tvar mode;\n\n\tfunction setMode( value ) {\n\n\t\tmode = value;\n\n\t}\n\n\tvar type, size;\n\n\tfunction setIndex( index ) {\n\n\t\tif ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) {\n\n\t\t\ttype = gl.UNSIGNED_INT;\n\t\t\tsize = 4;\n\n\t\t} else if ( index.array instanceof Uint16Array ) {\n\n\t\t\ttype = gl.UNSIGNED_SHORT;\n\t\t\tsize = 2;\n\n\t\t} else {\n\n\t\t\ttype = gl.UNSIGNED_BYTE;\n\t\t\tsize = 1;\n\n\t\t}\n\n\t}\n\n\tfunction render( start, count ) {\n\n\t\tgl.drawElements( mode, count, type, start * size );\n\n\t\tinfoRender.calls ++;\n\t\tinfoRender.vertices += count;\n\n\t\tif ( mode === gl.TRIANGLES ) infoRender.faces += count / 3;\n\n\t}\n\n\tfunction renderInstances( geometry, start, count ) {\n\n\t\tvar extension = extensions.get( 'ANGLE_instanced_arrays' );\n\n\t\tif ( extension === null ) {\n\n\t\t\tconsole.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\textension.drawElementsInstancedANGLE( mode, count, type, start * size, geometry.maxInstancedCount );\n\n\t\tinfoRender.calls ++;\n\t\tinfoRender.vertices += count * geometry.maxInstancedCount;\n\n\t\tif ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3;\n\n\t}\n\n\treturn {\n\n\t\tsetMode: setMode,\n\t\tsetIndex: setIndex,\n\t\trender: render,\n\t\trenderInstances: renderInstances\n\n\t};\n\n}\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction WebGLBufferRenderer( gl, extensions, infoRender ) {\n\n\tvar mode;\n\n\tfunction setMode( value ) {\n\n\t\tmode = value;\n\n\t}\n\n\tfunction render( start, count ) {\n\n\t\tgl.drawArrays( mode, start, count );\n\n\t\tinfoRender.calls ++;\n\t\tinfoRender.vertices += count;\n\n\t\tif ( mode === gl.TRIANGLES ) infoRender.faces += count / 3;\n\n\t}\n\n\tfunction renderInstances( geometry ) {\n\n\t\tvar extension = extensions.get( 'ANGLE_instanced_arrays' );\n\n\t\tif ( extension === null ) {\n\n\t\t\tconsole.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tvar position = geometry.attributes.position;\n\n\t\tvar count = 0;\n\n\t\tif ( position.isInterleavedBufferAttribute ) {\n\n\t\t\tcount = position.data.count;\n\n\t\t\textension.drawArraysInstancedANGLE( mode, 0, count, geometry.maxInstancedCount );\n\n\t\t} else {\n\n\t\t\tcount = position.count;\n\n\t\t\textension.drawArraysInstancedANGLE( mode, 0, count, geometry.maxInstancedCount );\n\n\t\t}\n\n\t\tinfoRender.calls ++;\n\t\tinfoRender.vertices += count * geometry.maxInstancedCount;\n\n\t\tif ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3;\n\n\t}\n\n\treturn {\n\t\tsetMode: setMode,\n\t\trender: render,\n\t\trenderInstances: renderInstances\n\t};\n\n}\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction WebGLLights() {\n\n\tvar lights = {};\n\n\treturn {\n\n\t\tget: function ( light ) {\n\n\t\t\tif ( lights[ light.id ] !== undefined ) {\n\n\t\t\t\treturn lights[ light.id ];\n\n\t\t\t}\n\n\t\t\tvar uniforms;\n\n\t\t\tswitch ( light.type ) {\n\n\t\t\t\tcase 'DirectionalLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tdirection: new Vector3(),\n\t\t\t\t\t\tcolor: new Color(),\n\n\t\t\t\t\t\tshadow: false,\n\t\t\t\t\t\tshadowBias: 0,\n\t\t\t\t\t\tshadowRadius: 1,\n\t\t\t\t\t\tshadowMapSize: new Vector2()\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'SpotLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tposition: new Vector3(),\n\t\t\t\t\t\tdirection: new Vector3(),\n\t\t\t\t\t\tcolor: new Color(),\n\t\t\t\t\t\tdistance: 0,\n\t\t\t\t\t\tconeCos: 0,\n\t\t\t\t\t\tpenumbraCos: 0,\n\t\t\t\t\t\tdecay: 0,\n\n\t\t\t\t\t\tshadow: false,\n\t\t\t\t\t\tshadowBias: 0,\n\t\t\t\t\t\tshadowRadius: 1,\n\t\t\t\t\t\tshadowMapSize: new Vector2()\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'PointLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tposition: new Vector3(),\n\t\t\t\t\t\tcolor: new Color(),\n\t\t\t\t\t\tdistance: 0,\n\t\t\t\t\t\tdecay: 0,\n\n\t\t\t\t\t\tshadow: false,\n\t\t\t\t\t\tshadowBias: 0,\n\t\t\t\t\t\tshadowRadius: 1,\n\t\t\t\t\t\tshadowMapSize: new Vector2()\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'HemisphereLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tdirection: new Vector3(),\n\t\t\t\t\t\tskyColor: new Color(),\n\t\t\t\t\t\tgroundColor: new Color()\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'RectAreaLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tcolor: new Color(),\n\t\t\t\t\t\tposition: new Vector3(),\n\t\t\t\t\t\thalfWidth: new Vector3(),\n\t\t\t\t\t\thalfHeight: new Vector3()\n\t\t\t\t\t\t// TODO (abelnation): set RectAreaLight shadow uniforms\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tlights[ light.id ] = uniforms;\n\n\t\t\treturn uniforms;\n\n\t\t}\n\n\t};\n\n}\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction addLineNumbers( string ) {\n\n\tvar lines = string.split( '\\n' );\n\n\tfor ( var i = 0; i < lines.length; i ++ ) {\n\n\t\tlines[ i ] = ( i + 1 ) + ': ' + lines[ i ];\n\n\t}\n\n\treturn lines.join( '\\n' );\n\n}\n\nfunction WebGLShader( gl, type, string ) {\n\n\tvar shader = gl.createShader( type );\n\n\tgl.shaderSource( shader, string );\n\tgl.compileShader( shader );\n\n\tif ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) {\n\n\t\tconsole.error( 'THREE.WebGLShader: Shader couldn\\'t compile.' );\n\n\t}\n\n\tif ( gl.getShaderInfoLog( shader ) !== '' ) {\n\n\t\tconsole.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', type === gl.VERTEX_SHADER ? 'vertex' : 'fragment', gl.getShaderInfoLog( shader ), addLineNumbers( string ) );\n\n\t}\n\n\t// --enable-privileged-webgl-extension\n\t// console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );\n\n\treturn shader;\n\n}\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nvar programIdCount = 0;\n\nfunction getEncodingComponents( encoding ) {\n\n\tswitch ( encoding ) {\n\n\t\tcase LinearEncoding:\n\t\t\treturn [ 'Linear','( value )' ];\n\t\tcase sRGBEncoding:\n\t\t\treturn [ 'sRGB','( value )' ];\n\t\tcase RGBEEncoding:\n\t\t\treturn [ 'RGBE','( value )' ];\n\t\tcase RGBM7Encoding:\n\t\t\treturn [ 'RGBM','( value, 7.0 )' ];\n\t\tcase RGBM16Encoding:\n\t\t\treturn [ 'RGBM','( value, 16.0 )' ];\n\t\tcase RGBDEncoding:\n\t\t\treturn [ 'RGBD','( value, 256.0 )' ];\n\t\tcase GammaEncoding:\n\t\t\treturn [ 'Gamma','( value, float( GAMMA_FACTOR ) )' ];\n\t\tdefault:\n\t\t\tthrow new Error( 'unsupported encoding: ' + encoding );\n\n\t}\n\n}\n\nfunction getTexelDecodingFunction( functionName, encoding ) {\n\n\tvar components = getEncodingComponents( encoding );\n\treturn \"vec4 \" + functionName + \"( vec4 value ) { return \" + components[ 0 ] + \"ToLinear\" + components[ 1 ] + \"; }\";\n\n}\n\nfunction getTexelEncodingFunction( functionName, encoding ) {\n\n\tvar components = getEncodingComponents( encoding );\n\treturn \"vec4 \" + functionName + \"( vec4 value ) { return LinearTo\" + components[ 0 ] + components[ 1 ] + \"; }\";\n\n}\n\nfunction getToneMappingFunction( functionName, toneMapping ) {\n\n\tvar toneMappingName;\n\n\tswitch ( toneMapping ) {\n\n\t\tcase LinearToneMapping:\n\t\t\ttoneMappingName = \"Linear\";\n\t\t\tbreak;\n\n\t\tcase ReinhardToneMapping:\n\t\t\ttoneMappingName = \"Reinhard\";\n\t\t\tbreak;\n\n\t\tcase Uncharted2ToneMapping:\n\t\t\ttoneMappingName = \"Uncharted2\";\n\t\t\tbreak;\n\n\t\tcase CineonToneMapping:\n\t\t\ttoneMappingName = \"OptimizedCineon\";\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new Error( 'unsupported toneMapping: ' + toneMapping );\n\n\t}\n\n\treturn \"vec3 \" + functionName + \"( vec3 color ) { return \" + toneMappingName + \"ToneMapping( color ); }\";\n\n}\n\nfunction generateExtensions( extensions, parameters, rendererExtensions ) {\n\n\textensions = extensions || {};\n\n\tvar chunks = [\n\t\t( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '',\n\t\t( extensions.fragDepth || parameters.logarithmicDepthBuffer ) && rendererExtensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '',\n\t\t( extensions.drawBuffers ) && rendererExtensions.get( 'WEBGL_draw_buffers' ) ? '#extension GL_EXT_draw_buffers : require' : '',\n\t\t( extensions.shaderTextureLOD || parameters.envMap ) && rendererExtensions.get( 'EXT_shader_texture_lod' ) ? '#extension GL_EXT_shader_texture_lod : enable' : ''\n\t];\n\n\treturn chunks.filter( filterEmptyLine ).join( '\\n' );\n\n}\n\nfunction generateDefines( defines ) {\n\n\tvar chunks = [];\n\n\tfor ( var name in defines ) {\n\n\t\tvar value = defines[ name ];\n\n\t\tif ( value === false ) continue;\n\n\t\tchunks.push( '#define ' + name + ' ' + value );\n\n\t}\n\n\treturn chunks.join( '\\n' );\n\n}\n\nfunction fetchAttributeLocations( gl, program, identifiers ) {\n\n\tvar attributes = {};\n\n\tvar n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES );\n\n\tfor ( var i = 0; i < n; i ++ ) {\n\n\t\tvar info = gl.getActiveAttrib( program, i );\n\t\tvar name = info.name;\n\n\t\t// console.log(\"THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:\", name, i );\n\n\t\tattributes[ name ] = gl.getAttribLocation( program, name );\n\n\t}\n\n\treturn attributes;\n\n}\n\nfunction filterEmptyLine( string ) {\n\n\treturn string !== '';\n\n}\n\nfunction replaceLightNums( string, parameters ) {\n\n\treturn string\n\t\t.replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )\n\t\t.replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )\n\t\t.replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )\n\t\t.replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )\n\t\t.replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights );\n\n}\n\nfunction parseIncludes( string ) {\n\n\tvar pattern = /#include +<([\\w\\d.]+)>/g;\n\n\tfunction replace( match, include ) {\n\n\t\tvar replace = ShaderChunk[ include ];\n\n\t\tif ( replace === undefined ) {\n\n\t\t\tthrow new Error( 'Can not resolve #include <' + include + '>' );\n\n\t\t}\n\n\t\treturn parseIncludes( replace );\n\n\t}\n\n\treturn string.replace( pattern, replace );\n\n}\n\nfunction unrollLoops( string ) {\n\n\tvar pattern = /for \\( int i \\= (\\d+)\\; i < (\\d+)\\; i \\+\\+ \\) \\{([\\s\\S]+?)(?=\\})\\}/g;\n\n\tfunction replace( match, start, end, snippet ) {\n\n\t\tvar unroll = '';\n\n\t\tfor ( var i = parseInt( start ); i < parseInt( end ); i ++ ) {\n\n\t\t\tunroll += snippet.replace( /\\[ i \\]/g, '[ ' + i + ' ]' );\n\n\t\t}\n\n\t\treturn unroll;\n\n\t}\n\n\treturn string.replace( pattern, replace );\n\n}\n\nfunction WebGLProgram( renderer, code, material, parameters ) {\n\n\tvar gl = renderer.context;\n\n\tvar extensions = material.extensions;\n\tvar defines = material.defines;\n\n\tvar vertexShader = material.__webglShader.vertexShader;\n\tvar fragmentShader = material.__webglShader.fragmentShader;\n\n\tvar shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';\n\n\tif ( parameters.shadowMapType === PCFShadowMap ) {\n\n\t\tshadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';\n\n\t} else if ( parameters.shadowMapType === PCFSoftShadowMap ) {\n\n\t\tshadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';\n\n\t}\n\n\tvar envMapTypeDefine = 'ENVMAP_TYPE_CUBE';\n\tvar envMapModeDefine = 'ENVMAP_MODE_REFLECTION';\n\tvar envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';\n\n\tif ( parameters.envMap ) {\n\n\t\tswitch ( material.envMap.mapping ) {\n\n\t\t\tcase CubeReflectionMapping:\n\t\t\tcase CubeRefractionMapping:\n\t\t\t\tenvMapTypeDefine = 'ENVMAP_TYPE_CUBE';\n\t\t\t\tbreak;\n\n\t\t\tcase CubeUVReflectionMapping:\n\t\t\tcase CubeUVRefractionMapping:\n\t\t\t\tenvMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';\n\t\t\t\tbreak;\n\n\t\t\tcase EquirectangularReflectionMapping:\n\t\t\tcase EquirectangularRefractionMapping:\n\t\t\t\tenvMapTypeDefine = 'ENVMAP_TYPE_EQUIREC';\n\t\t\t\tbreak;\n\n\t\t\tcase SphericalReflectionMapping:\n\t\t\t\tenvMapTypeDefine = 'ENVMAP_TYPE_SPHERE';\n\t\t\t\tbreak;\n\n\t\t}\n\n\t\tswitch ( material.envMap.mapping ) {\n\n\t\t\tcase CubeRefractionMapping:\n\t\t\tcase EquirectangularRefractionMapping:\n\t\t\t\tenvMapModeDefine = 'ENVMAP_MODE_REFRACTION';\n\t\t\t\tbreak;\n\n\t\t}\n\n\t\tswitch ( material.combine ) {\n\n\t\t\tcase MultiplyOperation:\n\t\t\t\tenvMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';\n\t\t\t\tbreak;\n\n\t\t\tcase MixOperation:\n\t\t\t\tenvMapBlendingDefine = 'ENVMAP_BLENDING_MIX';\n\t\t\t\tbreak;\n\n\t\t\tcase AddOperation:\n\t\t\t\tenvMapBlendingDefine = 'ENVMAP_BLENDING_ADD';\n\t\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n\tvar gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0;\n\n\t// console.log( 'building new program ' );\n\n\t//\n\n\tvar customExtensions = generateExtensions( extensions, parameters, renderer.extensions );\n\n\tvar customDefines = generateDefines( defines );\n\n\t//\n\n\tvar program = gl.createProgram();\n\n\tvar prefixVertex, prefixFragment;\n\n\tif ( material.isRawShaderMaterial ) {\n\n\t\tprefixVertex = [\n\n\t\t\tcustomDefines,\n\n\t\t\t'\\n'\n\n\t\t].filter( filterEmptyLine ).join( '\\n' );\n\n\t\tprefixFragment = [\n\n\t\t\tcustomExtensions,\n\t\t\tcustomDefines,\n\n\t\t\t'\\n'\n\n\t\t].filter( filterEmptyLine ).join( '\\n' );\n\n\t} else {\n\n\t\tprefixVertex = [\n\n \n\t\t\t'precision ' + parameters.precision + ' float;',\n\t\t\t'precision ' + parameters.precision + ' int;',\n\n\t\t\t'#define SHADER_NAME ' + material.__webglShader.name,\n\n\t\t\tcustomDefines,\n\n\t\t\tparameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',\n\n\t\t\t'#define GAMMA_FACTOR ' + gammaFactorDefine,\n\n\t\t\t'#define MAX_BONES ' + parameters.maxBones,\n\t\t\t( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',\n\t\t\t( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '',\n\n\n\t\t\tparameters.map ? '#define USE_MAP' : '',\n\t\t\tparameters.envMap ? '#define USE_ENVMAP' : '',\n\t\t\tparameters.envMap ? '#define ' + envMapModeDefine : '',\n\t\t\tparameters.lightMap ? '#define USE_LIGHTMAP' : '',\n\t\t\tparameters.aoMap ? '#define USE_AOMAP' : '',\n\t\t\tparameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',\n\t\t\tparameters.bumpMap ? '#define USE_BUMPMAP' : '',\n\t\t\tparameters.normalMap ? '#define USE_NORMALMAP' : '',\n\t\t\tparameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',\n\t\t\tparameters.specularMap ? '#define USE_SPECULARMAP' : '',\n\t\t\tparameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',\n\t\t\tparameters.metalnessMap ? '#define USE_METALNESSMAP' : '',\n\t\t\tparameters.alphaMap ? '#define USE_ALPHAMAP' : '',\n\t\t\tparameters.vertexColors ? '#define USE_COLOR' : '',\n\n\t\t\tparameters.flatShading ? '#define FLAT_SHADED' : '',\n\n\t\t\tparameters.skinning ? '#define USE_SKINNING' : '',\n\t\t\tparameters.useVertexTexture ? '#define BONE_TEXTURE' : '',\n\n\t\t\tparameters.morphTargets ? '#define USE_MORPHTARGETS' : '',\n\t\t\tparameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',\n\t\t\tparameters.doubleSided ? '#define DOUBLE_SIDED' : '',\n\t\t\tparameters.flipSided ? '#define FLIP_SIDED' : '',\n\n\t\t\t'#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes,\n\n\t\t\tparameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',\n\t\t\tparameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',\n\n\t\t\tparameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',\n\n\t\t\tparameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',\n\t\t\tparameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '',\n\n\t\t\t'uniform mat4 modelMatrix;',\n\t\t\t'uniform mat4 modelViewMatrix;',\n\t\t\t'uniform mat4 projectionMatrix;',\n\t\t\t'uniform mat4 viewMatrix;',\n\t\t\t'uniform mat3 normalMatrix;',\n\t\t\t'uniform vec3 cameraPosition;',\n\n\t\t\t'attribute vec3 position;',\n\t\t\t'attribute vec3 normal;',\n\t\t\t'attribute vec2 uv;',\n\n\t\t\t'#ifdef USE_COLOR',\n\n\t\t\t'\tattribute vec3 color;',\n\n\t\t\t'#endif',\n\n\t\t\t'#ifdef USE_MORPHTARGETS',\n\n\t\t\t'\tattribute vec3 morphTarget0;',\n\t\t\t'\tattribute vec3 morphTarget1;',\n\t\t\t'\tattribute vec3 morphTarget2;',\n\t\t\t'\tattribute vec3 morphTarget3;',\n\n\t\t\t'\t#ifdef USE_MORPHNORMALS',\n\n\t\t\t'\t\tattribute vec3 morphNormal0;',\n\t\t\t'\t\tattribute vec3 morphNormal1;',\n\t\t\t'\t\tattribute vec3 morphNormal2;',\n\t\t\t'\t\tattribute vec3 morphNormal3;',\n\n\t\t\t'\t#else',\n\n\t\t\t'\t\tattribute vec3 morphTarget4;',\n\t\t\t'\t\tattribute vec3 morphTarget5;',\n\t\t\t'\t\tattribute vec3 morphTarget6;',\n\t\t\t'\t\tattribute vec3 morphTarget7;',\n\n\t\t\t'\t#endif',\n\n\t\t\t'#endif',\n\n\t\t\t'#ifdef USE_SKINNING',\n\n\t\t\t'\tattribute vec4 skinIndex;',\n\t\t\t'\tattribute vec4 skinWeight;',\n\n\t\t\t'#endif',\n\n\t\t\t'\\n'\n\n\t\t].filter( filterEmptyLine ).join( '\\n' );\n\n\t\tprefixFragment = [\n\n\t\t\tcustomExtensions,\n\n\t\t\t'precision ' + parameters.precision + ' float;',\n\t\t\t'precision ' + parameters.precision + ' int;',\n\n\t\t\t'#define SHADER_NAME ' + material.__webglShader.name,\n\n\t\t\tcustomDefines,\n\n\t\t\tparameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '',\n\n\t\t\t'#define GAMMA_FACTOR ' + gammaFactorDefine,\n\n\t\t\t( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',\n\t\t\t( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '',\n\n\t\t\tparameters.map ? '#define USE_MAP' : '',\n\t\t\tparameters.envMap ? '#define USE_ENVMAP' : '',\n\t\t\tparameters.envMap ? '#define ' + envMapTypeDefine : '',\n\t\t\tparameters.envMap ? '#define ' + envMapModeDefine : '',\n\t\t\tparameters.envMap ? '#define ' + envMapBlendingDefine : '',\n\t\t\tparameters.lightMap ? '#define USE_LIGHTMAP' : '',\n\t\t\tparameters.aoMap ? '#define USE_AOMAP' : '',\n\t\t\tparameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',\n\t\t\tparameters.bumpMap ? '#define USE_BUMPMAP' : '',\n\t\t\tparameters.normalMap ? '#define USE_NORMALMAP' : '',\n\t\t\tparameters.specularMap ? '#define USE_SPECULARMAP' : '',\n\t\t\tparameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',\n\t\t\tparameters.metalnessMap ? '#define USE_METALNESSMAP' : '',\n\t\t\tparameters.alphaMap ? '#define USE_ALPHAMAP' : '',\n\t\t\tparameters.vertexColors ? '#define USE_COLOR' : '',\n\n\t\t\tparameters.gradientMap ? '#define USE_GRADIENTMAP' : '',\n\n\t\t\tparameters.flatShading ? '#define FLAT_SHADED' : '',\n\n\t\t\tparameters.doubleSided ? '#define DOUBLE_SIDED' : '',\n\t\t\tparameters.flipSided ? '#define FLIP_SIDED' : '',\n\n\t\t\t'#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes,\n\t\t\t'#define UNION_CLIPPING_PLANES ' + (parameters.numClippingPlanes - parameters.numClipIntersection),\n\n\t\t\tparameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',\n\t\t\tparameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',\n\n\t\t\tparameters.premultipliedAlpha ? \"#define PREMULTIPLIED_ALPHA\" : '',\n\n\t\t\tparameters.physicallyCorrectLights ? \"#define PHYSICALLY_CORRECT_LIGHTS\" : '',\n\n\t\t\tparameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',\n\t\t\tparameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '',\n\n\t\t\tparameters.envMap && renderer.extensions.get( 'EXT_shader_texture_lod' ) ? '#define TEXTURE_LOD_EXT' : '',\n\n\t\t\t'uniform mat4 viewMatrix;',\n\t\t\t'uniform vec3 cameraPosition;',\n\n\t\t\t( parameters.toneMapping !== NoToneMapping ) ? \"#define TONE_MAPPING\" : '',\n\t\t\t( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below\n\t\t\t( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( \"toneMapping\", parameters.toneMapping ) : '',\n\n\t\t\t( parameters.outputEncoding || parameters.mapEncoding || parameters.envMapEncoding || parameters.emissiveMapEncoding ) ? ShaderChunk[ 'encodings_pars_fragment' ] : '', // this code is required here because it is used by the various encoding/decoding function defined below\n\t\t\tparameters.mapEncoding ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '',\n\t\t\tparameters.envMapEncoding ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '',\n\t\t\tparameters.emissiveMapEncoding ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '',\n\t\t\tparameters.outputEncoding ? getTexelEncodingFunction( \"linearToOutputTexel\", parameters.outputEncoding ) : '',\n\n\t\t\tparameters.depthPacking ? \"#define DEPTH_PACKING \" + material.depthPacking : '',\n\n\t\t\t'\\n'\n\n\t\t].filter( filterEmptyLine ).join( '\\n' );\n\n\t}\n\n\tvertexShader = parseIncludes( vertexShader, parameters );\n\tvertexShader = replaceLightNums( vertexShader, parameters );\n\n\tfragmentShader = parseIncludes( fragmentShader, parameters );\n\tfragmentShader = replaceLightNums( fragmentShader, parameters );\n\n\tif ( ! material.isShaderMaterial ) {\n\n\t\tvertexShader = unrollLoops( vertexShader );\n\t\tfragmentShader = unrollLoops( fragmentShader );\n\n\t}\n\n\tvar vertexGlsl = prefixVertex + vertexShader;\n\tvar fragmentGlsl = prefixFragment + fragmentShader;\n\n\t// console.log( '*VERTEX*', vertexGlsl );\n\t// console.log( '*FRAGMENT*', fragmentGlsl );\n\n\tvar glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );\n\tvar glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );\n\n\tgl.attachShader( program, glVertexShader );\n\tgl.attachShader( program, glFragmentShader );\n\n\t// Force a particular attribute to index 0.\n\n\tif ( material.index0AttributeName !== undefined ) {\n\n\t\tgl.bindAttribLocation( program, 0, material.index0AttributeName );\n\n\t} else if ( parameters.morphTargets === true ) {\n\n\t\t// programs with morphTargets displace position out of attribute 0\n\t\tgl.bindAttribLocation( program, 0, 'position' );\n\n\t}\n\n\tgl.linkProgram( program );\n\n\tvar programLog = gl.getProgramInfoLog( program );\n\tvar vertexLog = gl.getShaderInfoLog( glVertexShader );\n\tvar fragmentLog = gl.getShaderInfoLog( glFragmentShader );\n\n\tvar runnable = true;\n\tvar haveDiagnostics = true;\n\n\t// console.log( '**VERTEX**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) );\n\t// console.log( '**FRAGMENT**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) );\n\n\tif ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) {\n\n\t\trunnable = false;\n\n\t\tconsole.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), 'gl.VALIDATE_STATUS', gl.getProgramParameter( program, gl.VALIDATE_STATUS ), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog );\n\n\t} else if ( programLog !== '' ) {\n\n\t\tconsole.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog );\n\n\t} else if ( vertexLog === '' || fragmentLog === '' ) {\n\n\t\thaveDiagnostics = false;\n\n\t}\n\n\tif ( haveDiagnostics ) {\n\n\t\tthis.diagnostics = {\n\n\t\t\trunnable: runnable,\n\t\t\tmaterial: material,\n\n\t\t\tprogramLog: programLog,\n\n\t\t\tvertexShader: {\n\n\t\t\t\tlog: vertexLog,\n\t\t\t\tprefix: prefixVertex\n\n\t\t\t},\n\n\t\t\tfragmentShader: {\n\n\t\t\t\tlog: fragmentLog,\n\t\t\t\tprefix: prefixFragment\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\t// clean up\n\n\tgl.deleteShader( glVertexShader );\n\tgl.deleteShader( glFragmentShader );\n\n\t// set up caching for uniform locations\n\n\tvar cachedUniforms;\n\n\tthis.getUniforms = function() {\n\n\t\tif ( cachedUniforms === undefined ) {\n\n\t\t\tcachedUniforms =\n\t\t\t\tnew WebGLUniforms( gl, program, renderer );\n\n\t\t}\n\n\t\treturn cachedUniforms;\n\n\t};\n\n\t// set up caching for attribute locations\n\n\tvar cachedAttributes;\n\n\tthis.getAttributes = function() {\n\n\t\tif ( cachedAttributes === undefined ) {\n\n\t\t\tcachedAttributes = fetchAttributeLocations( gl, program );\n\n\t\t}\n\n\t\treturn cachedAttributes;\n\n\t};\n\n\t// free resource\n\n\tthis.destroy = function() {\n\n\t\tgl.deleteProgram( program );\n\t\tthis.program = undefined;\n\n\t};\n\n\t// DEPRECATED\n\n\tObject.defineProperties( this, {\n\n\t\tuniforms: {\n\t\t\tget: function() {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLProgram: .uniforms is now .getUniforms().' );\n\t\t\t\treturn this.getUniforms();\n\n\t\t\t}\n\t\t},\n\n\t\tattributes: {\n\t\t\tget: function() {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLProgram: .attributes is now .getAttributes().' );\n\t\t\t\treturn this.getAttributes();\n\n\t\t\t}\n\t\t}\n\n\t} );\n\n\n\t//\n\n\tthis.id = programIdCount ++;\n\tthis.code = code;\n\tthis.usedTimes = 1;\n\tthis.program = program;\n\tthis.vertexShader = glVertexShader;\n\tthis.fragmentShader = glFragmentShader;\n\n\treturn this;\n\n}\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction WebGLPrograms( renderer, capabilities ) {\n\n\tvar programs = [];\n\n\tvar shaderIDs = {\n\t\tMeshDepthMaterial: 'depth',\n\t\tMeshNormalMaterial: 'normal',\n\t\tMeshBasicMaterial: 'basic',\n\t\tMeshLambertMaterial: 'lambert',\n\t\tMeshPhongMaterial: 'phong',\n\t\tMeshToonMaterial: 'phong',\n\t\tMeshStandardMaterial: 'physical',\n\t\tMeshPhysicalMaterial: 'physical',\n\t\tLineBasicMaterial: 'basic',\n\t\tLineDashedMaterial: 'dashed',\n\t\tPointsMaterial: 'points'\n\t};\n\n\tvar parameterNames = [\n\t\t\"precision\", \"supportsVertexTextures\", \"map\", \"mapEncoding\", \"envMap\", \"envMapMode\", \"envMapEncoding\",\n\t\t\"lightMap\", \"aoMap\", \"emissiveMap\", \"emissiveMapEncoding\", \"bumpMap\", \"normalMap\", \"displacementMap\", \"specularMap\",\n\t\t\"roughnessMap\", \"metalnessMap\", \"gradientMap\",\n\t\t\"alphaMap\", \"combine\", \"vertexColors\", \"fog\", \"useFog\", \"fogExp\",\n\t\t\"flatShading\", \"sizeAttenuation\", \"logarithmicDepthBuffer\", \"skinning\",\n\t\t\"maxBones\", \"useVertexTexture\", \"morphTargets\", \"morphNormals\",\n\t\t\"maxMorphTargets\", \"maxMorphNormals\", \"premultipliedAlpha\",\n\t\t\"numDirLights\", \"numPointLights\", \"numSpotLights\", \"numHemiLights\", \"numRectAreaLights\",\n\t\t\"shadowMapEnabled\", \"shadowMapType\", \"toneMapping\", 'physicallyCorrectLights',\n\t\t\"alphaTest\", \"doubleSided\", \"flipSided\", \"numClippingPlanes\", \"numClipIntersection\", \"depthPacking\"\n\t];\n\n\n\tfunction allocateBones( object ) {\n\n\t\tif ( capabilities.floatVertexTextures && object && object.skeleton && object.skeleton.useVertexTexture ) {\n\n\t\t\treturn 1024;\n\n\t\t} else {\n\n\t\t\t// default for when object is not specified\n\t\t\t// ( for example when prebuilding shader to be used with multiple objects )\n\t\t\t//\n\t\t\t// - leave some extra space for other uniforms\n\t\t\t// - limit here is ANGLE's 254 max uniform vectors\n\t\t\t// (up to 54 should be safe)\n\n\t\t\tvar nVertexUniforms = capabilities.maxVertexUniforms;\n\t\t\tvar nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );\n\n\t\t\tvar maxBones = nVertexMatrices;\n\n\t\t\tif ( object !== undefined && (object && object.isSkinnedMesh) ) {\n\n\t\t\t\tmaxBones = Math.min( object.skeleton.bones.length, maxBones );\n\n\t\t\t\tif ( maxBones < object.skeleton.bones.length ) {\n\n\t\t\t\t\tconsole.warn( 'WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn maxBones;\n\n\t\t}\n\n\t}\n\n\tfunction getTextureEncodingFromMap( map, gammaOverrideLinear ) {\n\n\t\tvar encoding;\n\n\t\tif ( ! map ) {\n\n\t\t\tencoding = LinearEncoding;\n\n\t\t} else if ( map.isTexture ) {\n\n\t\t\tencoding = map.encoding;\n\n\t\t} else if ( map.isWebGLRenderTarget ) {\n\n\t\t\tconsole.warn( \"THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead.\" );\n\t\t\tencoding = map.texture.encoding;\n\n\t\t}\n\n\t\t// add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point.\n\t\tif ( encoding === LinearEncoding && gammaOverrideLinear ) {\n\n\t\t\tencoding = GammaEncoding;\n\n\t\t}\n\n\t\treturn encoding;\n\n\t}\n\n\tthis.getParameters = function ( material, lights, fog, nClipPlanes, nClipIntersection, object ) {\n\n\t\tvar shaderID = shaderIDs[ material.type ];\n\n\t\t// heuristics to create shader parameters according to lights in the scene\n\t\t// (not to blow over maxLights budget)\n\n\t\tvar maxBones = allocateBones( object );\n\t\tvar precision = renderer.getPrecision();\n\n\t\tif ( material.precision !== null ) {\n\n\t\t\tprecision = capabilities.getMaxPrecision( material.precision );\n\n\t\t\tif ( precision !== material.precision ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar currentRenderTarget = renderer.getCurrentRenderTarget();\n\n\t\tvar parameters = {\n\n\t\t\tshaderID: shaderID,\n\n\t\t\tprecision: precision,\n\t\t\tsupportsVertexTextures: capabilities.vertexTextures,\n\t\t\toutputEncoding: getTextureEncodingFromMap( ( ! currentRenderTarget ) ? null : currentRenderTarget.texture, renderer.gammaOutput ),\n\t\t\tmap: !! material.map,\n\t\t\tmapEncoding: getTextureEncodingFromMap( material.map, renderer.gammaInput ),\n\t\t\tenvMap: !! material.envMap,\n\t\t\tenvMapMode: material.envMap && material.envMap.mapping,\n\t\t\tenvMapEncoding: getTextureEncodingFromMap( material.envMap, renderer.gammaInput ),\n\t\t\tenvMapCubeUV: ( !! material.envMap ) && ( ( material.envMap.mapping === CubeUVReflectionMapping ) || ( material.envMap.mapping === CubeUVRefractionMapping ) ),\n\t\t\tlightMap: !! material.lightMap,\n\t\t\taoMap: !! material.aoMap,\n\t\t\temissiveMap: !! material.emissiveMap,\n\t\t\temissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ),\n\t\t\tbumpMap: !! material.bumpMap,\n\t\t\tnormalMap: !! material.normalMap,\n\t\t\tdisplacementMap: !! material.displacementMap,\n\t\t\troughnessMap: !! material.roughnessMap,\n\t\t\tmetalnessMap: !! material.metalnessMap,\n\t\t\tspecularMap: !! material.specularMap,\n\t\t\talphaMap: !! material.alphaMap,\n\n\t\t\tgradientMap: !! material.gradientMap,\n\n\t\t\tcombine: material.combine,\n\n\t\t\tvertexColors: material.vertexColors,\n\n\t\t\tfog: !! fog,\n\t\t\tuseFog: material.fog,\n\t\t\tfogExp: (fog && fog.isFogExp2),\n\n\t\t\tflatShading: material.shading === FlatShading,\n\n\t\t\tsizeAttenuation: material.sizeAttenuation,\n\t\t\tlogarithmicDepthBuffer: capabilities.logarithmicDepthBuffer,\n\n\t\t\tskinning: material.skinning,\n\t\t\tmaxBones: maxBones,\n\t\t\tuseVertexTexture: capabilities.floatVertexTextures && object && object.skeleton && object.skeleton.useVertexTexture,\n\n\t\t\tmorphTargets: material.morphTargets,\n\t\t\tmorphNormals: material.morphNormals,\n\t\t\tmaxMorphTargets: renderer.maxMorphTargets,\n\t\t\tmaxMorphNormals: renderer.maxMorphNormals,\n\n\t\t\tnumDirLights: lights.directional.length,\n\t\t\tnumPointLights: lights.point.length,\n\t\t\tnumSpotLights: lights.spot.length,\n\t\t\tnumRectAreaLights: lights.rectArea.length,\n\t\t\tnumHemiLights: lights.hemi.length,\n\n\t\t\tnumClippingPlanes: nClipPlanes,\n\t\t\tnumClipIntersection: nClipIntersection,\n\n\t\t\tshadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && lights.shadows.length > 0,\n\t\t\tshadowMapType: renderer.shadowMap.type,\n\n\t\t\ttoneMapping: renderer.toneMapping,\n\t\t\tphysicallyCorrectLights: renderer.physicallyCorrectLights,\n\n\t\t\tpremultipliedAlpha: material.premultipliedAlpha,\n\n\t\t\talphaTest: material.alphaTest,\n\t\t\tdoubleSided: material.side === DoubleSide,\n\t\t\tflipSided: material.side === BackSide,\n\n\t\t\tdepthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false\n\n\t\t};\n\n\t\treturn parameters;\n\n\t};\n\n\tthis.getProgramCode = function ( material, parameters ) {\n\n\t\tvar array = [];\n\n\t\tif ( parameters.shaderID ) {\n\n\t\t\tarray.push( parameters.shaderID );\n\n\t\t} else {\n\n\t\t\tarray.push( material.fragmentShader );\n\t\t\tarray.push( material.vertexShader );\n\n\t\t}\n\n\t\tif ( material.defines !== undefined ) {\n\n\t\t\tfor ( var name in material.defines ) {\n\n\t\t\t\tarray.push( name );\n\t\t\t\tarray.push( material.defines[ name ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfor ( var i = 0; i < parameterNames.length; i ++ ) {\n\n\t\t\tarray.push( parameters[ parameterNames[ i ] ] );\n\n\t\t}\n\n\t\treturn array.join();\n\n\t};\n\n\tthis.acquireProgram = function ( material, parameters, code ) {\n\n\t\tvar program;\n\n\t\t// Check if code has been already compiled\n\t\tfor ( var p = 0, pl = programs.length; p < pl; p ++ ) {\n\n\t\t\tvar programInfo = programs[ p ];\n\n\t\t\tif ( programInfo.code === code ) {\n\n\t\t\t\tprogram = programInfo;\n\t\t\t\t++ program.usedTimes;\n\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( program === undefined ) {\n\n\t\t\tprogram = new WebGLProgram( renderer, code, material, parameters );\n\t\t\tprograms.push( program );\n\n\t\t}\n\n\t\treturn program;\n\n\t};\n\n\tthis.releaseProgram = function( program ) {\n\n\t\tif ( -- program.usedTimes === 0 ) {\n\n\t\t\t// Remove from unordered set\n\t\t\tvar i = programs.indexOf( program );\n\t\t\tprograms[ i ] = programs[ programs.length - 1 ];\n\t\t\tprograms.pop();\n\n\t\t\t// Free WebGL resources\n\t\t\tprogram.destroy();\n\n\t\t}\n\n\t};\n\n\t// Exposed for resource monitoring & error feedback via renderer.info:\n\tthis.programs = programs;\n\n}\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction WebGLGeometries( gl, properties, info ) {\n\n\tvar geometries = {};\n\n\tfunction onGeometryDispose( event ) {\n\n\t\tvar geometry = event.target;\n\t\tvar buffergeometry = geometries[ geometry.id ];\n\n\t\tif ( buffergeometry.index !== null ) {\n\n\t\t\tdeleteAttribute( buffergeometry.index );\n\n\t\t}\n\n\t\tdeleteAttributes( buffergeometry.attributes );\n\n\t\tgeometry.removeEventListener( 'dispose', onGeometryDispose );\n\n\t\tdelete geometries[ geometry.id ];\n\n\t\t// TODO\n\n\t\tvar property = properties.get( geometry );\n\n\t\tif ( property.wireframe ) {\n\n\t\t\tdeleteAttribute( property.wireframe );\n\n\t\t}\n\n\t\tproperties.delete( geometry );\n\n\t\tvar bufferproperty = properties.get( buffergeometry );\n\n\t\tif ( bufferproperty.wireframe ) {\n\n\t\t\tdeleteAttribute( bufferproperty.wireframe );\n\n\t\t}\n\n\t\tproperties.delete( buffergeometry );\n\n\t\t//\n\n\t\tinfo.memory.geometries --;\n\n\t}\n\n\tfunction getAttributeBuffer( attribute ) {\n\n\t\tif ( attribute.isInterleavedBufferAttribute ) {\n\n\t\t\treturn properties.get( attribute.data ).__webglBuffer;\n\n\t\t}\n\n\t\treturn properties.get( attribute ).__webglBuffer;\n\n\t}\n\n\tfunction deleteAttribute( attribute ) {\n\n\t\tvar buffer = getAttributeBuffer( attribute );\n\n\t\tif ( buffer !== undefined ) {\n\n\t\t\tgl.deleteBuffer( buffer );\n\t\t\tremoveAttributeBuffer( attribute );\n\n\t\t}\n\n\t}\n\n\tfunction deleteAttributes( attributes ) {\n\n\t\tfor ( var name in attributes ) {\n\n\t\t\tdeleteAttribute( attributes[ name ] );\n\n\t\t}\n\n\t}\n\n\tfunction removeAttributeBuffer( attribute ) {\n\n\t\tif ( attribute.isInterleavedBufferAttribute ) {\n\n\t\t\tproperties.delete( attribute.data );\n\n\t\t} else {\n\n\t\t\tproperties.delete( attribute );\n\n\t\t}\n\n\t}\n\n\treturn {\n\n\t\tget: function ( object ) {\n\n\t\t\tvar geometry = object.geometry;\n\n\t\t\tif ( geometries[ geometry.id ] !== undefined ) {\n\n\t\t\t\treturn geometries[ geometry.id ];\n\n\t\t\t}\n\n\t\t\tgeometry.addEventListener( 'dispose', onGeometryDispose );\n\n\t\t\tvar buffergeometry;\n\n\t\t\tif ( geometry.isBufferGeometry ) {\n\n\t\t\t\tbuffergeometry = geometry;\n\n\t\t\t} else if ( geometry.isGeometry ) {\n\n\t\t\t\tif ( geometry._bufferGeometry === undefined ) {\n\n\t\t\t\t\tgeometry._bufferGeometry = new BufferGeometry().setFromObject( object );\n\n\t\t\t\t}\n\n\t\t\t\tbuffergeometry = geometry._bufferGeometry;\n\n\t\t\t}\n\n\t\t\tgeometries[ geometry.id ] = buffergeometry;\n\n\t\t\tinfo.memory.geometries ++;\n\n\t\t\treturn buffergeometry;\n\n\t\t}\n\n\t};\n\n}\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction WebGLObjects( gl, properties, info ) {\n\n\tvar geometries = new WebGLGeometries( gl, properties, info );\n\n\t//\n\n\tfunction update( object ) {\n\n\t\t// TODO: Avoid updating twice (when using shadowMap). Maybe add frame counter.\n\n\t\tvar geometry = geometries.get( object );\n\n\t\tif ( object.geometry.isGeometry ) {\n\n\t\t\tgeometry.updateFromObject( object );\n\n\t\t}\n\n\t\tvar index = geometry.index;\n\t\tvar attributes = geometry.attributes;\n\n\t\tif ( index !== null ) {\n\n\t\t\tupdateAttribute( index, gl.ELEMENT_ARRAY_BUFFER );\n\n\t\t}\n\n\t\tfor ( var name in attributes ) {\n\n\t\t\tupdateAttribute( attributes[ name ], gl.ARRAY_BUFFER );\n\n\t\t}\n\n\t\t// morph targets\n\n\t\tvar morphAttributes = geometry.morphAttributes;\n\n\t\tfor ( var name in morphAttributes ) {\n\n\t\t\tvar array = morphAttributes[ name ];\n\n\t\t\tfor ( var i = 0, l = array.length; i < l; i ++ ) {\n\n\t\t\t\tupdateAttribute( array[ i ], gl.ARRAY_BUFFER );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn geometry;\n\n\t}\n\n\tfunction updateAttribute( attribute, bufferType ) {\n\n\t\tvar data = ( attribute.isInterleavedBufferAttribute ) ? attribute.data : attribute;\n\n\t\tvar attributeProperties = properties.get( data );\n\n\t\tif ( attributeProperties.__webglBuffer === undefined ) {\n\n\t\t\tcreateBuffer( attributeProperties, data, bufferType );\n\n\t\t} else if ( attributeProperties.version !== data.version ) {\n\n\t\t\tupdateBuffer( attributeProperties, data, bufferType );\n\n\t\t}\n\n\t}\n\n\tfunction createBuffer( attributeProperties, data, bufferType ) {\n\n\t\tattributeProperties.__webglBuffer = gl.createBuffer();\n\t\tgl.bindBuffer( bufferType, attributeProperties.__webglBuffer );\n\n\t\tvar usage = data.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW;\n\n\t\tgl.bufferData( bufferType, data.array, usage );\n\n\t\tvar type = gl.FLOAT;\n\t\tvar array = data.array;\n\n\t\tif ( array instanceof Float32Array ) {\n\n\t\t\ttype = gl.FLOAT;\n\n\t\t} else if ( array instanceof Float64Array ) {\n\n\t\t\tconsole.warn( \"Unsupported data buffer format: Float64Array\" );\n\n\t\t} else if ( array instanceof Uint16Array ) {\n\n\t\t\ttype = gl.UNSIGNED_SHORT;\n\n\t\t} else if ( array instanceof Int16Array ) {\n\n\t\t\ttype = gl.SHORT;\n\n\t\t} else if ( array instanceof Uint32Array ) {\n\n\t\t\ttype = gl.UNSIGNED_INT;\n\n\t\t} else if ( array instanceof Int32Array ) {\n\n\t\t\ttype = gl.INT;\n\n\t\t} else if ( array instanceof Int8Array ) {\n\n\t\t\ttype = gl.BYTE;\n\n\t\t} else if ( array instanceof Uint8Array ) {\n\n\t\t\ttype = gl.UNSIGNED_BYTE;\n\n\t\t}\n\n\t\tattributeProperties.bytesPerElement = array.BYTES_PER_ELEMENT;\n\t\tattributeProperties.type = type;\n\t\tattributeProperties.version = data.version;\n\n\t\tdata.onUploadCallback();\n\n\t}\n\n\tfunction updateBuffer( attributeProperties, data, bufferType ) {\n\n\t\tgl.bindBuffer( bufferType, attributeProperties.__webglBuffer );\n\n\t\tif ( data.dynamic === false ) {\n\n\t\t\tgl.bufferData( bufferType, data.array, gl.STATIC_DRAW );\n\n\t\t} else if ( data.updateRange.count === - 1 ) {\n\n\t\t\t// Not using update ranges\n\n\t\t\tgl.bufferSubData( bufferType, 0, data.array );\n\n\t\t} else if ( data.updateRange.count === 0 ) {\n\n\t\t\tconsole.error( 'THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually.' );\n\n\t\t} else {\n\n\t\t\tgl.bufferSubData( bufferType, data.updateRange.offset * data.array.BYTES_PER_ELEMENT,\n\t\t\t\t\t\t\t data.array.subarray( data.updateRange.offset, data.updateRange.offset + data.updateRange.count ) );\n\n\t\t\tdata.updateRange.count = 0; // reset range\n\n\t\t}\n\n\t\tattributeProperties.version = data.version;\n\n\t}\n\n\tfunction getAttributeBuffer( attribute ) {\n\n\t\tif ( attribute.isInterleavedBufferAttribute ) {\n\n\t\t\treturn properties.get( attribute.data ).__webglBuffer;\n\n\t\t}\n\n\t\treturn properties.get( attribute ).__webglBuffer;\n\n\t}\n\n\tfunction getAttributeProperties( attribute ) {\n\n\t\tif ( attribute.isInterleavedBufferAttribute ) {\n\n\t\t\treturn properties.get( attribute.data );\n\n\t\t}\n\n\t\treturn properties.get( attribute );\n\n\t}\n\n\tfunction getWireframeAttribute( geometry ) {\n\n\t\tvar property = properties.get( geometry );\n\n\t\tif ( property.wireframe !== undefined ) {\n\n\t\t\treturn property.wireframe;\n\n\t\t}\n\n\t\tvar indices = [];\n\n\t\tvar index = geometry.index;\n\t\tvar attributes = geometry.attributes;\n\n\t\t// console.time( 'wireframe' );\n\n\t\tif ( index !== null ) {\n\n\t\t\tvar array = index.array;\n\n\t\t\tfor ( var i = 0, l = array.length; i < l; i += 3 ) {\n\n\t\t\t\tvar a = array[ i + 0 ];\n\t\t\t\tvar b = array[ i + 1 ];\n\t\t\t\tvar c = array[ i + 2 ];\n\n\t\t\t\tindices.push( a, b, b, c, c, a );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tvar array = attributes.position.array;\n\n\t\t\tfor ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {\n\n\t\t\t\tvar a = i + 0;\n\t\t\t\tvar b = i + 1;\n\t\t\t\tvar c = i + 2;\n\n\t\t\t\tindices.push( a, b, b, c, c, a );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// console.timeEnd( 'wireframe' );\n\n\t\tvar attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );\n\n\t\tupdateAttribute( attribute, gl.ELEMENT_ARRAY_BUFFER );\n\n\t\tproperty.wireframe = attribute;\n\n\t\treturn attribute;\n\n\t}\n\n\treturn {\n\n\t\tgetAttributeBuffer: getAttributeBuffer,\n\t\tgetAttributeProperties: getAttributeProperties,\n\t\tgetWireframeAttribute: getWireframeAttribute,\n\n\t\tupdate: update\n\n\t};\n\n}\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, info ) {\n\n\tvar _infoMemory = info.memory;\n\tvar _isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && _gl instanceof WebGL2RenderingContext );\n\n\t//\n\n\tfunction clampToMaxSize( image, maxSize ) {\n\n\t\tif ( image.width > maxSize || image.height > maxSize ) {\n\n\t\t\t// Warning: Scaling through the canvas will only work with images that use\n\t\t\t// premultiplied alpha.\n\n\t\t\tvar scale = maxSize / Math.max( image.width, image.height );\n\n\t\t\tvar canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );\n\t\t\tcanvas.width = Math.floor( image.width * scale );\n\t\t\tcanvas.height = Math.floor( image.height * scale );\n\n\t\t\tvar context = canvas.getContext( '2d' );\n\t\t\tcontext.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height );\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image );\n\n\t\t\treturn canvas;\n\n\t\t}\n\n\t\treturn image;\n\n\t}\n\n\tfunction isPowerOfTwo( image ) {\n\n\t\treturn _Math.isPowerOfTwo( image.width ) && _Math.isPowerOfTwo( image.height );\n\n\t}\n\n\tfunction makePowerOfTwo( image ) {\n\n\t\tif ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement ) {\n\n\t\t\tvar canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );\n\t\t\tcanvas.width = _Math.nearestPowerOfTwo( image.width );\n\t\t\tcanvas.height = _Math.nearestPowerOfTwo( image.height );\n\n\t\t\tvar context = canvas.getContext( '2d' );\n\t\t\tcontext.drawImage( image, 0, 0, canvas.width, canvas.height );\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: image is not power of two (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image );\n\n\t\t\treturn canvas;\n\n\t\t}\n\n\t\treturn image;\n\n\t}\n\n\tfunction textureNeedsPowerOfTwo( texture ) {\n\n\t\treturn ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||\n\t\t\t( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );\n\n\t}\n\n\t// Fallback filters for non-power-of-2 textures\n\n\tfunction filterFallback( f ) {\n\n\t\tif ( f === NearestFilter || f === NearestMipMapNearestFilter || f === NearestMipMapLinearFilter ) {\n\n\t\t\treturn _gl.NEAREST;\n\n\t\t}\n\n\t\treturn _gl.LINEAR;\n\n\t}\n\n\t//\n\n\tfunction onTextureDispose( event ) {\n\n\t\tvar texture = event.target;\n\n\t\ttexture.removeEventListener( 'dispose', onTextureDispose );\n\n\t\tdeallocateTexture( texture );\n\n\t\t_infoMemory.textures --;\n\n\n\t}\n\n\tfunction onRenderTargetDispose( event ) {\n\n\t\tvar renderTarget = event.target;\n\n\t\trenderTarget.removeEventListener( 'dispose', onRenderTargetDispose );\n\n\t\tdeallocateRenderTarget( renderTarget );\n\n\t\t_infoMemory.textures --;\n\n\t}\n\n\t//\n\n\tfunction deallocateTexture( texture ) {\n\n\t\tvar textureProperties = properties.get( texture );\n\n\t\tif ( texture.image && textureProperties.__image__webglTextureCube ) {\n\n\t\t\t// cube texture\n\n\t\t\t_gl.deleteTexture( textureProperties.__image__webglTextureCube );\n\n\t\t} else {\n\n\t\t\t// 2D texture\n\n\t\t\tif ( textureProperties.__webglInit === undefined ) return;\n\n\t\t\t_gl.deleteTexture( textureProperties.__webglTexture );\n\n\t\t}\n\n\t\t// remove all webgl properties\n\t\tproperties.delete( texture );\n\n\t}\n\n\tfunction deallocateRenderTarget( renderTarget ) {\n\n\t\tvar renderTargetProperties = properties.get( renderTarget );\n\t\tvar textureProperties = properties.get( renderTarget.texture );\n\n\t\tif ( ! renderTarget ) return;\n\n\t\tif ( textureProperties.__webglTexture !== undefined ) {\n\n\t\t\t_gl.deleteTexture( textureProperties.__webglTexture );\n\n\t\t}\n\n\t\tif ( renderTarget.depthTexture ) {\n\n\t\t\trenderTarget.depthTexture.dispose();\n\n\t\t}\n\n\t\tif ( renderTarget.isWebGLRenderTargetCube ) {\n\n\t\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\t\t_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );\n\t\t\t\tif ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );\n\t\t\tif ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );\n\n\t\t}\n\n\t\tproperties.delete( renderTarget.texture );\n\t\tproperties.delete( renderTarget );\n\n\t}\n\n\t//\n\n\n\n\tfunction setTexture2D( texture, slot ) {\n\n\t\tvar textureProperties = properties.get( texture );\n\n\t\tif ( texture.version > 0 && textureProperties.__version !== texture.version ) {\n\n\t\t\tvar image = texture.image;\n\n\t\t\tif ( image === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined', texture );\n\n\t\t\t} else if ( image.complete === false ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete', texture );\n\n\t\t\t} else {\n\n\t\t\t\tuploadTexture( textureProperties, texture, slot );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t}\n\n\t\tstate.activeTexture( _gl.TEXTURE0 + slot );\n\t\tstate.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );\n\n\t}\n\n\tfunction setTextureCube( texture, slot ) {\n\n\t\tvar textureProperties = properties.get( texture );\n\n\t\tif ( texture.image.length === 6 ) {\n\n\t\t\tif ( texture.version > 0 && textureProperties.__version !== texture.version ) {\n\n\t\t\t\tif ( ! textureProperties.__image__webglTextureCube ) {\n\n\t\t\t\t\ttexture.addEventListener( 'dispose', onTextureDispose );\n\n\t\t\t\t\ttextureProperties.__image__webglTextureCube = _gl.createTexture();\n\n\t\t\t\t\t_infoMemory.textures ++;\n\n\t\t\t\t}\n\n\t\t\t\tstate.activeTexture( _gl.TEXTURE0 + slot );\n\t\t\t\tstate.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube );\n\n\t\t\t\t_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );\n\n\t\t\t\tvar isCompressed = ( texture && texture.isCompressedTexture );\n\t\t\t\tvar isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );\n\n\t\t\t\tvar cubeImage = [];\n\n\t\t\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\t\t\tif ( ! isCompressed && ! isDataTexture ) {\n\n\t\t\t\t\t\tcubeImage[ i ] = clampToMaxSize( texture.image[ i ], capabilities.maxCubemapSize );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tcubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tvar image = cubeImage[ 0 ],\n\t\t\t\tisPowerOfTwoImage = isPowerOfTwo( image ),\n\t\t\t\tglFormat = paramThreeToGL( texture.format ),\n\t\t\t\tglType = paramThreeToGL( texture.type );\n\n\t\t\t\tsetTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isPowerOfTwoImage );\n\n\t\t\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\t\t\tif ( ! isCompressed ) {\n\n\t\t\t\t\t\tif ( isDataTexture ) {\n\n\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tvar mipmap, mipmaps = cubeImage[ i ].mipmaps;\n\n\t\t\t\t\t\tfor ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {\n\n\t\t\t\t\t\t\tmipmap = mipmaps[ j ];\n\n\t\t\t\t\t\t\tif ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {\n\n\t\t\t\t\t\t\t\tif ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {\n\n\t\t\t\t\t\t\t\t\tstate.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );\n\n\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\tconsole.warn( \"THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()\" );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( texture.generateMipmaps && isPowerOfTwoImage ) {\n\n\t\t\t\t\t_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );\n\n\t\t\t\t}\n\n\t\t\t\ttextureProperties.__version = texture.version;\n\n\t\t\t\tif ( texture.onUpdate ) texture.onUpdate( texture );\n\n\t\t\t} else {\n\n\t\t\t\tstate.activeTexture( _gl.TEXTURE0 + slot );\n\t\t\t\tstate.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction setTextureCubeDynamic( texture, slot ) {\n\n\t\tstate.activeTexture( _gl.TEXTURE0 + slot );\n\t\tstate.bindTexture( _gl.TEXTURE_CUBE_MAP, properties.get( texture ).__webglTexture );\n\n\t}\n\n\tfunction setTextureParameters( textureType, texture, isPowerOfTwoImage ) {\n\n\t\tvar extension;\n\n\t\tif ( isPowerOfTwoImage ) {\n\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) );\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) );\n\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) );\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) );\n\n\t\t} else {\n\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );\n\n\t\t\tif ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.', texture );\n\n\t\t\t}\n\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );\n\n\t\t\tif ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.', texture );\n\n\t\t\t}\n\n\t\t}\n\n\t\textension = extensions.get( 'EXT_texture_filter_anisotropic' );\n\n\t\tif ( extension ) {\n\n\t\t\tif ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return;\n\t\t\tif ( texture.type === HalfFloatType && extensions.get( 'OES_texture_half_float_linear' ) === null ) return;\n\n\t\t\tif ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {\n\n\t\t\t\t_gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );\n\t\t\t\tproperties.get( texture ).__currentAnisotropy = texture.anisotropy;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction uploadTexture( textureProperties, texture, slot ) {\n\n\t\tif ( textureProperties.__webglInit === undefined ) {\n\n\t\t\ttextureProperties.__webglInit = true;\n\n\t\t\ttexture.addEventListener( 'dispose', onTextureDispose );\n\n\t\t\ttextureProperties.__webglTexture = _gl.createTexture();\n\n\t\t\t_infoMemory.textures ++;\n\n\t\t}\n\n\t\tstate.activeTexture( _gl.TEXTURE0 + slot );\n\t\tstate.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );\n\n\t\t_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );\n\t\t_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );\n\t\t_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );\n\n\t\tvar image = clampToMaxSize( texture.image, capabilities.maxTextureSize );\n\n\t\tif ( textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( image ) === false ) {\n\n\t\t\timage = makePowerOfTwo( image );\n\n\t\t}\n\n\t\tvar isPowerOfTwoImage = isPowerOfTwo( image ),\n\t\tglFormat = paramThreeToGL( texture.format ),\n\t\tglType = paramThreeToGL( texture.type );\n\n\t\tsetTextureParameters( _gl.TEXTURE_2D, texture, isPowerOfTwoImage );\n\n\t\tvar mipmap, mipmaps = texture.mipmaps;\n\n\t\tif ( texture.isDepthTexture ) {\n\n\t\t\t// populate depth texture with dummy data\n\n\t\t\tvar internalFormat = _gl.DEPTH_COMPONENT;\n\n\t\t\tif ( texture.type === FloatType ) {\n\n\t\t\t\tif ( !_isWebGL2 ) throw new Error('Float Depth Texture only supported in WebGL2.0');\n\t\t\t\tinternalFormat = _gl.DEPTH_COMPONENT32F;\n\n\t\t\t} else if ( _isWebGL2 ) {\n\n\t\t\t\t// WebGL 2.0 requires signed internalformat for glTexImage2D\n\t\t\t\tinternalFormat = _gl.DEPTH_COMPONENT16;\n\n\t\t\t}\n\n\t\t\tif ( texture.format === DepthFormat && internalFormat === _gl.DEPTH_COMPONENT ) {\n\n\t\t\t\t// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are\n\t\t\t\t// DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT\n\t\t\t\t// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)\n\t\t\t\tif ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {\n\n\t\t\t\t console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );\n\n\t\t\t\t\ttexture.type = UnsignedShortType;\n\t\t\t\t\tglType = paramThreeToGL( texture.type );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// Depth stencil textures need the DEPTH_STENCIL internal format\n\t\t\t// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)\n\t\t\tif ( texture.format === DepthStencilFormat ) {\n\n\t\t\t\tinternalFormat = _gl.DEPTH_STENCIL;\n\n\t\t\t\t// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are\n\t\t\t\t// DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.\n\t\t\t\t// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)\n\t\t\t\tif ( texture.type !== UnsignedInt248Type ) {\n\n\t\t\t\t console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );\n\n\t\t\t\t\ttexture.type = UnsignedInt248Type;\n\t\t\t\t\tglType = paramThreeToGL( texture.type );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tstate.texImage2D( _gl.TEXTURE_2D, 0, internalFormat, image.width, image.height, 0, glFormat, glType, null );\n\n\t\t} else if ( texture.isDataTexture ) {\n\n\t\t\t// use manually created mipmaps if available\n\t\t\t// if there are no manual mipmaps\n\t\t\t// set 0 level mipmap and then use GL to generate other mipmap levels\n\n\t\t\tif ( mipmaps.length > 0 && isPowerOfTwoImage ) {\n\n\t\t\t\tfor ( var i = 0, il = mipmaps.length; i < il; i ++ ) {\n\n\t\t\t\t\tmipmap = mipmaps[ i ];\n\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );\n\n\t\t\t\t}\n\n\t\t\t\ttexture.generateMipmaps = false;\n\n\t\t\t} else {\n\n\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );\n\n\t\t\t}\n\n\t\t} else if ( texture.isCompressedTexture ) {\n\n\t\t\tfor ( var i = 0, il = mipmaps.length; i < il; i ++ ) {\n\n\t\t\t\tmipmap = mipmaps[ i ];\n\n\t\t\t\tif ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {\n\n\t\t\t\t\tif ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {\n\n\t\t\t\t\t\tstate.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconsole.warn( \"THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()\" );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// regular Texture (image, video, canvas)\n\n\t\t\t// use manually created mipmaps if available\n\t\t\t// if there are no manual mipmaps\n\t\t\t// set 0 level mipmap and then use GL to generate other mipmap levels\n\n\t\t\tif ( mipmaps.length > 0 && isPowerOfTwoImage ) {\n\n\t\t\t\tfor ( var i = 0, il = mipmaps.length; i < il; i ++ ) {\n\n\t\t\t\t\tmipmap = mipmaps[ i ];\n\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );\n\n\t\t\t\t}\n\n\t\t\t\ttexture.generateMipmaps = false;\n\n\t\t\t} else {\n\n\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, image );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( texture.generateMipmaps && isPowerOfTwoImage ) _gl.generateMipmap( _gl.TEXTURE_2D );\n\n\t\ttextureProperties.__version = texture.version;\n\n\t\tif ( texture.onUpdate ) texture.onUpdate( texture );\n\n\t}\n\n\t// Render targets\n\n\t// Setup storage for target texture and bind it to correct framebuffer\n\tfunction setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) {\n\n\t\tvar glFormat = paramThreeToGL( renderTarget.texture.format );\n\t\tvar glType = paramThreeToGL( renderTarget.texture.type );\n\t\tstate.texImage2D( textureTarget, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );\n\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\t\t_gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 );\n\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );\n\n\t}\n\n\t// Setup storage for internal depth/stencil buffers and bind to correct framebuffer\n\tfunction setupRenderBufferStorage( renderbuffer, renderTarget ) {\n\n\t\t_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );\n\n\t\tif ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {\n\n\t\t\t_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );\n\t\t\t_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );\n\n\t\t} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {\n\n\t\t\t_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );\n\t\t\t_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );\n\n\t\t} else {\n\n\t\t\t// FIXME: We don't support !depth !stencil\n\t\t\t_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );\n\n\t\t}\n\n\t\t_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );\n\n\t}\n\n\t// Setup resources for a Depth Texture for a FBO (needs an extension)\n\tfunction setupDepthTexture( framebuffer, renderTarget ) {\n\n\t\tvar isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube );\n\t\tif ( isCube ) throw new Error('Depth Texture with cube render targets is not supported!');\n\n\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\tif ( !( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {\n\n\t\t\tthrow new Error('renderTarget.depthTexture must be an instance of THREE.DepthTexture');\n\n\t\t}\n\n\t\t// upload an empty depth texture with framebuffer size\n\t\tif ( !properties.get( renderTarget.depthTexture ).__webglTexture ||\n\t\t\t\trenderTarget.depthTexture.image.width !== renderTarget.width ||\n\t\t\t\trenderTarget.depthTexture.image.height !== renderTarget.height ) {\n\t\t\trenderTarget.depthTexture.image.width = renderTarget.width;\n\t\t\trenderTarget.depthTexture.image.height = renderTarget.height;\n\t\t\trenderTarget.depthTexture.needsUpdate = true;\n\t\t}\n\n\t\tsetTexture2D( renderTarget.depthTexture, 0 );\n\n\t\tvar webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;\n\n\t\tif ( renderTarget.depthTexture.format === DepthFormat ) {\n\n\t\t\t_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );\n\n\t\t} else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {\n\n\t\t\t_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );\n\n\t\t} else {\n\n\t\t\tthrow new Error('Unknown depthTexture format')\n\n\t\t}\n\n\t}\n\n\t// Setup GL resources for a non-texture depth buffer\n\tfunction setupDepthRenderbuffer( renderTarget ) {\n\n\t\tvar renderTargetProperties = properties.get( renderTarget );\n\n\t\tvar isCube = ( renderTarget.isWebGLRenderTargetCube === true );\n\n\t\tif ( renderTarget.depthTexture ) {\n\n\t\t\tif ( isCube ) throw new Error('target.depthTexture not supported in Cube render targets');\n\n\t\t\tsetupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );\n\n\t\t} else {\n\n\t\t\tif ( isCube ) {\n\n\t\t\t\trenderTargetProperties.__webglDepthbuffer = [];\n\n\t\t\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );\n\t\t\t\t\trenderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();\n\t\t\t\t\tsetupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );\n\t\t\t\trenderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();\n\t\t\t\tsetupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget );\n\n\t\t\t}\n\n\t\t}\n\n\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );\n\n\t}\n\n\t// Set up GL resources for the render target\n\tfunction setupRenderTarget( renderTarget ) {\n\n\t\tvar renderTargetProperties = properties.get( renderTarget );\n\t\tvar textureProperties = properties.get( renderTarget.texture );\n\n\t\trenderTarget.addEventListener( 'dispose', onRenderTargetDispose );\n\n\t\ttextureProperties.__webglTexture = _gl.createTexture();\n\n\t\t_infoMemory.textures ++;\n\n\t\tvar isCube = ( renderTarget.isWebGLRenderTargetCube === true );\n\t\tvar isTargetPowerOfTwo = isPowerOfTwo( renderTarget );\n\n\t\t// Setup framebuffer\n\n\t\tif ( isCube ) {\n\n\t\t\trenderTargetProperties.__webglFramebuffer = [];\n\n\t\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\t\trenderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\trenderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();\n\n\t\t}\n\n\t\t// Setup color buffer\n\n\t\tif ( isCube ) {\n\n\t\t\tstate.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );\n\t\t\tsetTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, isTargetPowerOfTwo );\n\n\t\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\t\tsetupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );\n\n\t\t\t}\n\n\t\t\tif ( renderTarget.texture.generateMipmaps && isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );\n\t\t\tstate.bindTexture( _gl.TEXTURE_CUBE_MAP, null );\n\n\t\t} else {\n\n\t\t\tstate.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );\n\t\t\tsetTextureParameters( _gl.TEXTURE_2D, renderTarget.texture, isTargetPowerOfTwo );\n\t\t\tsetupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D );\n\n\t\t\tif ( renderTarget.texture.generateMipmaps && isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );\n\t\t\tstate.bindTexture( _gl.TEXTURE_2D, null );\n\n\t\t}\n\n\t\t// Setup depth and stencil buffers\n\n\t\tif ( renderTarget.depthBuffer ) {\n\n\t\t\tsetupDepthRenderbuffer( renderTarget );\n\n\t\t}\n\n\t}\n\n\tfunction updateRenderTargetMipmap( renderTarget ) {\n\n\t\tvar texture = renderTarget.texture;\n\n\t\tif ( texture.generateMipmaps && isPowerOfTwo( renderTarget ) &&\n\t\t\t\ttexture.minFilter !== NearestFilter &&\n\t\t\t\ttexture.minFilter !== LinearFilter ) {\n\n\t\t\tvar target = (renderTarget && renderTarget.isWebGLRenderTargetCube) ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D;\n\t\t\tvar webglTexture = properties.get( texture ).__webglTexture;\n\n\t\t\tstate.bindTexture( target, webglTexture );\n\t\t\t_gl.generateMipmap( target );\n\t\t\tstate.bindTexture( target, null );\n\n\t\t}\n\n\t}\n\n\tthis.setTexture2D = setTexture2D;\n\tthis.setTextureCube = setTextureCube;\n\tthis.setTextureCubeDynamic = setTextureCubeDynamic;\n\tthis.setupRenderTarget = setupRenderTarget;\n\tthis.updateRenderTargetMipmap = updateRenderTargetMipmap;\n\n}\n\n/**\n * @author fordacious / fordacious.github.io\n */\n\nfunction WebGLProperties() {\n\n\tvar properties = {};\n\n\treturn {\n\n\t\tget: function ( object ) {\n\n\t\t\tvar uuid = object.uuid;\n\t\t\tvar map = properties[ uuid ];\n\n\t\t\tif ( map === undefined ) {\n\n\t\t\t\tmap = {};\n\t\t\t\tproperties[ uuid ] = map;\n\n\t\t\t}\n\n\t\t\treturn map;\n\n\t\t},\n\n\t\tdelete: function ( object ) {\n\n\t\t\tdelete properties[ object.uuid ];\n\n\t\t},\n\n\t\tclear: function () {\n\n\t\t\tproperties = {};\n\n\t\t}\n\n\t};\n\n}\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction WebGLState( gl, extensions, paramThreeToGL ) {\n\n\tfunction ColorBuffer() {\n\n\t\tvar locked = false;\n\n\t\tvar color = new Vector4();\n\t\tvar currentColorMask = null;\n\t\tvar currentColorClear = new Vector4();\n\n\t\treturn {\n\n\t\t\tsetMask: function ( colorMask ) {\n\n\t\t\t\tif ( currentColorMask !== colorMask && ! locked ) {\n\n\t\t\t\t\tgl.colorMask( colorMask, colorMask, colorMask, colorMask );\n\t\t\t\t\tcurrentColorMask = colorMask;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetLocked: function ( lock ) {\n\n\t\t\t\tlocked = lock;\n\n\t\t\t},\n\n\t\t\tsetClear: function ( r, g, b, a, premultipliedAlpha ) {\n\n\t\t\t\tif ( premultipliedAlpha === true ) {\n\n\t\t\t\t\tr *= a; g *= a; b *= a;\n\n\t\t\t\t}\n\n\t\t\t\tcolor.set( r, g, b, a );\n\n\t\t\t\tif ( currentColorClear.equals( color ) === false ) {\n\n\t\t\t\t\tgl.clearColor( r, g, b, a );\n\t\t\t\t\tcurrentColorClear.copy( color );\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\treset: function () {\n\n\t\t\t\tlocked = false;\n\n\t\t\t\tcurrentColorMask = null;\n\t\t\t\tcurrentColorClear.set( 0, 0, 0, 1 );\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\tfunction DepthBuffer() {\n\n\t\tvar locked = false;\n\n\t\tvar currentDepthMask = null;\n\t\tvar currentDepthFunc = null;\n\t\tvar currentDepthClear = null;\n\n\t\treturn {\n\n\t\t\tsetTest: function ( depthTest ) {\n\n\t\t\t\tif ( depthTest ) {\n\n\t\t\t\t\tenable( gl.DEPTH_TEST );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tdisable( gl.DEPTH_TEST );\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetMask: function ( depthMask ) {\n\n\t\t\t\tif ( currentDepthMask !== depthMask && ! locked ) {\n\n\t\t\t\t\tgl.depthMask( depthMask );\n\t\t\t\t\tcurrentDepthMask = depthMask;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetFunc: function ( depthFunc ) {\n\n\t\t\t\tif ( currentDepthFunc !== depthFunc ) {\n\n\t\t\t\t\tif ( depthFunc ) {\n\n\t\t\t\t\t\tswitch ( depthFunc ) {\n\n\t\t\t\t\t\t\tcase NeverDepth:\n\n\t\t\t\t\t\t\t\tgl.depthFunc( gl.NEVER );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase AlwaysDepth:\n\n\t\t\t\t\t\t\t\tgl.depthFunc( gl.ALWAYS );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase LessDepth:\n\n\t\t\t\t\t\t\t\tgl.depthFunc( gl.LESS );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase LessEqualDepth:\n\n\t\t\t\t\t\t\t\tgl.depthFunc( gl.LEQUAL );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase EqualDepth:\n\n\t\t\t\t\t\t\t\tgl.depthFunc( gl.EQUAL );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase GreaterEqualDepth:\n\n\t\t\t\t\t\t\t\tgl.depthFunc( gl.GEQUAL );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase GreaterDepth:\n\n\t\t\t\t\t\t\t\tgl.depthFunc( gl.GREATER );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase NotEqualDepth:\n\n\t\t\t\t\t\t\t\tgl.depthFunc( gl.NOTEQUAL );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\t\tgl.depthFunc( gl.LEQUAL );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tgl.depthFunc( gl.LEQUAL );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tcurrentDepthFunc = depthFunc;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetLocked: function ( lock ) {\n\n\t\t\t\tlocked = lock;\n\n\t\t\t},\n\n\t\t\tsetClear: function ( depth ) {\n\n\t\t\t\tif ( currentDepthClear !== depth ) {\n\n\t\t\t\t\tgl.clearDepth( depth );\n\t\t\t\t\tcurrentDepthClear = depth;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\treset: function () {\n\n\t\t\t\tlocked = false;\n\n\t\t\t\tcurrentDepthMask = null;\n\t\t\t\tcurrentDepthFunc = null;\n\t\t\t\tcurrentDepthClear = null;\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\tfunction StencilBuffer() {\n\n\t\tvar locked = false;\n\n\t\tvar currentStencilMask = null;\n\t\tvar currentStencilFunc = null;\n\t\tvar currentStencilRef = null;\n\t\tvar currentStencilFuncMask = null;\n\t\tvar currentStencilFail = null;\n\t\tvar currentStencilZFail = null;\n\t\tvar currentStencilZPass = null;\n\t\tvar currentStencilClear = null;\n\n\t\treturn {\n\n\t\t\tsetTest: function ( stencilTest ) {\n\n\t\t\t\tif ( stencilTest ) {\n\n\t\t\t\t\tenable( gl.STENCIL_TEST );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tdisable( gl.STENCIL_TEST );\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetMask: function ( stencilMask ) {\n\n\t\t\t\tif ( currentStencilMask !== stencilMask && ! locked ) {\n\n\t\t\t\t\tgl.stencilMask( stencilMask );\n\t\t\t\t\tcurrentStencilMask = stencilMask;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetFunc: function ( stencilFunc, stencilRef, stencilMask ) {\n\n\t\t\t\tif ( currentStencilFunc !== stencilFunc ||\n\t\t\t\t currentStencilRef \t!== stencilRef \t||\n\t\t\t\t currentStencilFuncMask !== stencilMask ) {\n\n\t\t\t\t\tgl.stencilFunc( stencilFunc, stencilRef, stencilMask );\n\n\t\t\t\t\tcurrentStencilFunc = stencilFunc;\n\t\t\t\t\tcurrentStencilRef = stencilRef;\n\t\t\t\t\tcurrentStencilFuncMask = stencilMask;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetOp: function ( stencilFail, stencilZFail, stencilZPass ) {\n\n\t\t\t\tif ( currentStencilFail\t !== stencilFail \t||\n\t\t\t\t currentStencilZFail !== stencilZFail ||\n\t\t\t\t currentStencilZPass !== stencilZPass ) {\n\n\t\t\t\t\tgl.stencilOp( stencilFail, stencilZFail, stencilZPass );\n\n\t\t\t\t\tcurrentStencilFail = stencilFail;\n\t\t\t\t\tcurrentStencilZFail = stencilZFail;\n\t\t\t\t\tcurrentStencilZPass = stencilZPass;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetLocked: function ( lock ) {\n\n\t\t\t\tlocked = lock;\n\n\t\t\t},\n\n\t\t\tsetClear: function ( stencil ) {\n\n\t\t\t\tif ( currentStencilClear !== stencil ) {\n\n\t\t\t\t\tgl.clearStencil( stencil );\n\t\t\t\t\tcurrentStencilClear = stencil;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\treset: function () {\n\n\t\t\t\tlocked = false;\n\n\t\t\t\tcurrentStencilMask = null;\n\t\t\t\tcurrentStencilFunc = null;\n\t\t\t\tcurrentStencilRef = null;\n\t\t\t\tcurrentStencilFuncMask = null;\n\t\t\t\tcurrentStencilFail = null;\n\t\t\t\tcurrentStencilZFail = null;\n\t\t\t\tcurrentStencilZPass = null;\n\t\t\t\tcurrentStencilClear = null;\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\t//\n\n\tvar colorBuffer = new ColorBuffer();\n\tvar depthBuffer = new DepthBuffer();\n\tvar stencilBuffer = new StencilBuffer();\n\n\tvar maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );\n\tvar newAttributes = new Uint8Array( maxVertexAttributes );\n\tvar enabledAttributes = new Uint8Array( maxVertexAttributes );\n\tvar attributeDivisors = new Uint8Array( maxVertexAttributes );\n\n\tvar capabilities = {};\n\n\tvar compressedTextureFormats = null;\n\n\tvar currentBlending = null;\n\tvar currentBlendEquation = null;\n\tvar currentBlendSrc = null;\n\tvar currentBlendDst = null;\n\tvar currentBlendEquationAlpha = null;\n\tvar currentBlendSrcAlpha = null;\n\tvar currentBlendDstAlpha = null;\n\tvar currentPremultipledAlpha = false;\n\n\tvar currentFlipSided = null;\n\tvar currentCullFace = null;\n\n\tvar currentLineWidth = null;\n\n\tvar currentPolygonOffsetFactor = null;\n\tvar currentPolygonOffsetUnits = null;\n\n\tvar currentScissorTest = null;\n\n\tvar maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS );\n\n\tvar version = parseFloat( /^WebGL\\ ([0-9])/.exec( gl.getParameter( gl.VERSION ) )[ 1 ] );\n\tvar lineWidthAvailable = parseFloat( version ) >= 1.0;\n\n\tvar currentTextureSlot = null;\n\tvar currentBoundTextures = {};\n\n\tvar currentScissor = new Vector4();\n\tvar currentViewport = new Vector4();\n\n\tfunction createTexture( type, target, count ) {\n\n\t\tvar data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.\n\t\tvar texture = gl.createTexture();\n\n\t\tgl.bindTexture( type, texture );\n\t\tgl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST );\n\t\tgl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST );\n\n\t\tfor ( var i = 0; i < count; i ++ ) {\n\n\t\t\tgl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );\n\n\t\t}\n\n\t\treturn texture;\n\n\t}\n\n\tvar emptyTextures = {};\n\temptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 );\n\temptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 );\n\n\t//\n\n\tfunction init() {\n\n\t\tcolorBuffer.setClear( 0, 0, 0, 1 );\n\t\tdepthBuffer.setClear( 1 );\n\t\tstencilBuffer.setClear( 0 );\n\n\t\tenable( gl.DEPTH_TEST );\n\t\tsetDepthFunc( LessEqualDepth );\n\n\t\tsetFlipSided( false );\n\t\tsetCullFace( CullFaceBack );\n\t\tenable( gl.CULL_FACE );\n\n\t\tenable( gl.BLEND );\n\t\tsetBlending( NormalBlending );\n\n\t}\n\n\tfunction initAttributes() {\n\n\t\tfor ( var i = 0, l = newAttributes.length; i < l; i ++ ) {\n\n\t\t\tnewAttributes[ i ] = 0;\n\n\t\t}\n\n\t}\n\n\tfunction enableAttribute( attribute ) {\n\n\t\tnewAttributes[ attribute ] = 1;\n\n\t\tif ( enabledAttributes[ attribute ] === 0 ) {\n\n\t\t\tgl.enableVertexAttribArray( attribute );\n\t\t\tenabledAttributes[ attribute ] = 1;\n\n\t\t}\n\n\t\tif ( attributeDivisors[ attribute ] !== 0 ) {\n\n\t\t\tvar extension = extensions.get( 'ANGLE_instanced_arrays' );\n\n\t\t\textension.vertexAttribDivisorANGLE( attribute, 0 );\n\t\t\tattributeDivisors[ attribute ] = 0;\n\n\t\t}\n\n\t}\n\n\tfunction enableAttributeAndDivisor( attribute, meshPerAttribute, extension ) {\n\n\t\tnewAttributes[ attribute ] = 1;\n\n\t\tif ( enabledAttributes[ attribute ] === 0 ) {\n\n\t\t\tgl.enableVertexAttribArray( attribute );\n\t\t\tenabledAttributes[ attribute ] = 1;\n\n\t\t}\n\n\t\tif ( attributeDivisors[ attribute ] !== meshPerAttribute ) {\n\n\t\t\textension.vertexAttribDivisorANGLE( attribute, meshPerAttribute );\n\t\t\tattributeDivisors[ attribute ] = meshPerAttribute;\n\n\t\t}\n\n\t}\n\n\tfunction disableUnusedAttributes() {\n\n\t\tfor ( var i = 0, l = enabledAttributes.length; i !== l; ++ i ) {\n\n\t\t\tif ( enabledAttributes[ i ] !== newAttributes[ i ] ) {\n\n\t\t\t\tgl.disableVertexAttribArray( i );\n\t\t\t\tenabledAttributes[ i ] = 0;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction enable( id ) {\n\n\t\tif ( capabilities[ id ] !== true ) {\n\n\t\t\tgl.enable( id );\n\t\t\tcapabilities[ id ] = true;\n\n\t\t}\n\n\t}\n\n\tfunction disable( id ) {\n\n\t\tif ( capabilities[ id ] !== false ) {\n\n\t\t\tgl.disable( id );\n\t\t\tcapabilities[ id ] = false;\n\n\t\t}\n\n\t}\n\n\tfunction getCompressedTextureFormats() {\n\n\t\tif ( compressedTextureFormats === null ) {\n\n\t\t\tcompressedTextureFormats = [];\n\n\t\t\tif ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) ||\n\t\t\t extensions.get( 'WEBGL_compressed_texture_s3tc' ) ||\n\t\t\t extensions.get( 'WEBGL_compressed_texture_etc1' ) ) {\n\n\t\t\t\tvar formats = gl.getParameter( gl.COMPRESSED_TEXTURE_FORMATS );\n\n\t\t\t\tfor ( var i = 0; i < formats.length; i ++ ) {\n\n\t\t\t\t\tcompressedTextureFormats.push( formats[ i ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn compressedTextureFormats;\n\n\t}\n\n\tfunction setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {\n\n\t\tif ( blending !== NoBlending ) {\n\n\t\t\tenable( gl.BLEND );\n\n\t\t} else {\n\n\t\t\tdisable( gl.BLEND );\n\n\t\t}\n\n\t\tif ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {\n\n\t\t\tif ( blending === AdditiveBlending ) {\n\n\t\t\t\tif ( premultipliedAlpha ) {\n\n\t\t\t\t\tgl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );\n\t\t\t\t\tgl.blendFuncSeparate( gl.ONE, gl.ONE, gl.ONE, gl.ONE );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tgl.blendEquation( gl.FUNC_ADD );\n\t\t\t\t\tgl.blendFunc( gl.SRC_ALPHA, gl.ONE );\n\n\t\t\t\t}\n\n\t\t\t} else if ( blending === SubtractiveBlending ) {\n\n\t\t\t\tif ( premultipliedAlpha ) {\n\n\t\t\t\t\tgl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );\n\t\t\t\t\tgl.blendFuncSeparate( gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tgl.blendEquation( gl.FUNC_ADD );\n\t\t\t\t\tgl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR );\n\n\t\t\t\t}\n\n\t\t\t} else if ( blending === MultiplyBlending ) {\n\n\t\t\t\tif ( premultipliedAlpha ) {\n\n\t\t\t\t\tgl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );\n\t\t\t\t\tgl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tgl.blendEquation( gl.FUNC_ADD );\n\t\t\t\t\tgl.blendFunc( gl.ZERO, gl.SRC_COLOR );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tif ( premultipliedAlpha ) {\n\n\t\t\t\t\tgl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );\n\t\t\t\t\tgl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tgl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );\n\t\t\t\t\tgl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tcurrentBlending = blending;\n\t\t\tcurrentPremultipledAlpha = premultipliedAlpha;\n\n\t\t}\n\n\t\tif ( blending === CustomBlending ) {\n\n\t\t\tblendEquationAlpha = blendEquationAlpha || blendEquation;\n\t\t\tblendSrcAlpha = blendSrcAlpha || blendSrc;\n\t\t\tblendDstAlpha = blendDstAlpha || blendDst;\n\n\t\t\tif ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {\n\n\t\t\t\tgl.blendEquationSeparate( paramThreeToGL( blendEquation ), paramThreeToGL( blendEquationAlpha ) );\n\n\t\t\t\tcurrentBlendEquation = blendEquation;\n\t\t\t\tcurrentBlendEquationAlpha = blendEquationAlpha;\n\n\t\t\t}\n\n\t\t\tif ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {\n\n\t\t\t\tgl.blendFuncSeparate( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ), paramThreeToGL( blendSrcAlpha ), paramThreeToGL( blendDstAlpha ) );\n\n\t\t\t\tcurrentBlendSrc = blendSrc;\n\t\t\t\tcurrentBlendDst = blendDst;\n\t\t\t\tcurrentBlendSrcAlpha = blendSrcAlpha;\n\t\t\t\tcurrentBlendDstAlpha = blendDstAlpha;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tcurrentBlendEquation = null;\n\t\t\tcurrentBlendSrc = null;\n\t\t\tcurrentBlendDst = null;\n\t\t\tcurrentBlendEquationAlpha = null;\n\t\t\tcurrentBlendSrcAlpha = null;\n\t\t\tcurrentBlendDstAlpha = null;\n\n\t\t}\n\n\t}\n\n\t// TODO Deprecate\n\n\tfunction setColorWrite( colorWrite ) {\n\n\t\tcolorBuffer.setMask( colorWrite );\n\n\t}\n\n\tfunction setDepthTest( depthTest ) {\n\n\t\tdepthBuffer.setTest( depthTest );\n\n\t}\n\n\tfunction setDepthWrite( depthWrite ) {\n\n\t\tdepthBuffer.setMask( depthWrite );\n\n\t}\n\n\tfunction setDepthFunc( depthFunc ) {\n\n\t\tdepthBuffer.setFunc( depthFunc );\n\n\t}\n\n\tfunction setStencilTest( stencilTest ) {\n\n\t\tstencilBuffer.setTest( stencilTest );\n\n\t}\n\n\tfunction setStencilWrite( stencilWrite ) {\n\n\t\tstencilBuffer.setMask( stencilWrite );\n\n\t}\n\n\tfunction setStencilFunc( stencilFunc, stencilRef, stencilMask ) {\n\n\t\tstencilBuffer.setFunc( stencilFunc, stencilRef, stencilMask );\n\n\t}\n\n\tfunction setStencilOp( stencilFail, stencilZFail, stencilZPass ) {\n\n\t\tstencilBuffer.setOp( stencilFail, stencilZFail, stencilZPass );\n\n\t}\n\n\t//\n\n\tfunction setFlipSided( flipSided ) {\n\n\t\tif ( currentFlipSided !== flipSided ) {\n\n\t\t\tif ( flipSided ) {\n\n\t\t\t\tgl.frontFace( gl.CW );\n\n\t\t\t} else {\n\n\t\t\t\tgl.frontFace( gl.CCW );\n\n\t\t\t}\n\n\t\t\tcurrentFlipSided = flipSided;\n\n\t\t}\n\n\t}\n\n\tfunction setCullFace( cullFace ) {\n\n\t\tif ( cullFace !== CullFaceNone ) {\n\n\t\t\tenable( gl.CULL_FACE );\n\n\t\t\tif ( cullFace !== currentCullFace ) {\n\n\t\t\t\tif ( cullFace === CullFaceBack ) {\n\n\t\t\t\t\tgl.cullFace( gl.BACK );\n\n\t\t\t\t} else if ( cullFace === CullFaceFront ) {\n\n\t\t\t\t\tgl.cullFace( gl.FRONT );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tgl.cullFace( gl.FRONT_AND_BACK );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tdisable( gl.CULL_FACE );\n\n\t\t}\n\n\t\tcurrentCullFace = cullFace;\n\n\t}\n\n\tfunction setLineWidth( width ) {\n\n\t\tif ( width !== currentLineWidth ) {\n\n\t\t\tif ( lineWidthAvailable ) gl.lineWidth( width );\n\n\t\t\tcurrentLineWidth = width;\n\n\t\t}\n\n\t}\n\n\tfunction setPolygonOffset( polygonOffset, factor, units ) {\n\n\t\tif ( polygonOffset ) {\n\n\t\t\tenable( gl.POLYGON_OFFSET_FILL );\n\n\t\t\tif ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {\n\n\t\t\t\tgl.polygonOffset( factor, units );\n\n\t\t\t\tcurrentPolygonOffsetFactor = factor;\n\t\t\t\tcurrentPolygonOffsetUnits = units;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tdisable( gl.POLYGON_OFFSET_FILL );\n\n\t\t}\n\n\t}\n\n\tfunction getScissorTest() {\n\n\t\treturn currentScissorTest;\n\n\t}\n\n\tfunction setScissorTest( scissorTest ) {\n\n\t\tcurrentScissorTest = scissorTest;\n\n\t\tif ( scissorTest ) {\n\n\t\t\tenable( gl.SCISSOR_TEST );\n\n\t\t} else {\n\n\t\t\tdisable( gl.SCISSOR_TEST );\n\n\t\t}\n\n\t}\n\n\t// texture\n\n\tfunction activeTexture( webglSlot ) {\n\n\t\tif ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;\n\n\t\tif ( currentTextureSlot !== webglSlot ) {\n\n\t\t\tgl.activeTexture( webglSlot );\n\t\t\tcurrentTextureSlot = webglSlot;\n\n\t\t}\n\n\t}\n\n\tfunction bindTexture( webglType, webglTexture ) {\n\n\t\tif ( currentTextureSlot === null ) {\n\n\t\t\tactiveTexture();\n\n\t\t}\n\n\t\tvar boundTexture = currentBoundTextures[ currentTextureSlot ];\n\n\t\tif ( boundTexture === undefined ) {\n\n\t\t\tboundTexture = { type: undefined, texture: undefined };\n\t\t\tcurrentBoundTextures[ currentTextureSlot ] = boundTexture;\n\n\t\t}\n\n\t\tif ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {\n\n\t\t\tgl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );\n\n\t\t\tboundTexture.type = webglType;\n\t\t\tboundTexture.texture = webglTexture;\n\n\t\t}\n\n\t}\n\n\tfunction compressedTexImage2D() {\n\n\t\ttry {\n\n\t\t\tgl.compressedTexImage2D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( error );\n\n\t\t}\n\n\t}\n\n\tfunction texImage2D() {\n\n\t\ttry {\n\n\t\t\tgl.texImage2D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( error );\n\n\t\t}\n\n\t}\n\n\t//\n\n\tfunction scissor( scissor ) {\n\n\t\tif ( currentScissor.equals( scissor ) === false ) {\n\n\t\t\tgl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );\n\t\t\tcurrentScissor.copy( scissor );\n\n\t\t}\n\n\t}\n\n\tfunction viewport( viewport ) {\n\n\t\tif ( currentViewport.equals( viewport ) === false ) {\n\n\t\t\tgl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );\n\t\t\tcurrentViewport.copy( viewport );\n\n\t\t}\n\n\t}\n\n\t//\n\n\tfunction reset() {\n\n\t\tfor ( var i = 0; i < enabledAttributes.length; i ++ ) {\n\n\t\t\tif ( enabledAttributes[ i ] === 1 ) {\n\n\t\t\t\tgl.disableVertexAttribArray( i );\n\t\t\t\tenabledAttributes[ i ] = 0;\n\n\t\t\t}\n\n\t\t}\n\n\t\tcapabilities = {};\n\n\t\tcompressedTextureFormats = null;\n\n\t\tcurrentTextureSlot = null;\n\t\tcurrentBoundTextures = {};\n\n\t\tcurrentBlending = null;\n\n\t\tcurrentFlipSided = null;\n\t\tcurrentCullFace = null;\n\n\t\tcolorBuffer.reset();\n\t\tdepthBuffer.reset();\n\t\tstencilBuffer.reset();\n\n\t}\n\n\treturn {\n\n\t\tbuffers: {\n\t\t\tcolor: colorBuffer,\n\t\t\tdepth: depthBuffer,\n\t\t\tstencil: stencilBuffer\n\t\t},\n\n\t\tinit: init,\n\t\tinitAttributes: initAttributes,\n\t\tenableAttribute: enableAttribute,\n\t\tenableAttributeAndDivisor: enableAttributeAndDivisor,\n\t\tdisableUnusedAttributes: disableUnusedAttributes,\n\t\tenable: enable,\n\t\tdisable: disable,\n\t\tgetCompressedTextureFormats: getCompressedTextureFormats,\n\n\t\tsetBlending: setBlending,\n\n\t\tsetColorWrite: setColorWrite,\n\t\tsetDepthTest: setDepthTest,\n\t\tsetDepthWrite: setDepthWrite,\n\t\tsetDepthFunc: setDepthFunc,\n\t\tsetStencilTest: setStencilTest,\n\t\tsetStencilWrite: setStencilWrite,\n\t\tsetStencilFunc: setStencilFunc,\n\t\tsetStencilOp: setStencilOp,\n\n\t\tsetFlipSided: setFlipSided,\n\t\tsetCullFace: setCullFace,\n\n\t\tsetLineWidth: setLineWidth,\n\t\tsetPolygonOffset: setPolygonOffset,\n\n\t\tgetScissorTest: getScissorTest,\n\t\tsetScissorTest: setScissorTest,\n\n\t\tactiveTexture: activeTexture,\n\t\tbindTexture: bindTexture,\n\t\tcompressedTexImage2D: compressedTexImage2D,\n\t\ttexImage2D: texImage2D,\n\n\t\tscissor: scissor,\n\t\tviewport: viewport,\n\n\t\treset: reset\n\n\t};\n\n}\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction WebGLCapabilities( gl, extensions, parameters ) {\n\n\tvar maxAnisotropy;\n\n\tfunction getMaxAnisotropy() {\n\n\t\tif ( maxAnisotropy !== undefined ) return maxAnisotropy;\n\n\t\tvar extension = extensions.get( 'EXT_texture_filter_anisotropic' );\n\n\t\tif ( extension !== null ) {\n\n\t\t\tmaxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );\n\n\t\t} else {\n\n\t\t\tmaxAnisotropy = 0;\n\n\t\t}\n\n\t\treturn maxAnisotropy;\n\n\t}\n\n\tfunction getMaxPrecision( precision ) {\n\n\t\tif ( precision === 'highp' ) {\n\n\t\t\tif ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 &&\n\t\t\t gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) {\n\n\t\t\t\treturn 'highp';\n\n\t\t\t}\n\n\t\t\tprecision = 'mediump';\n\n\t\t}\n\n\t\tif ( precision === 'mediump' ) {\n\n\t\t\tif ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 &&\n\t\t\t gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) {\n\n\t\t\t\treturn 'mediump';\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn 'lowp';\n\n\t}\n\n\tvar precision = parameters.precision !== undefined ? parameters.precision : 'highp';\n\tvar maxPrecision = getMaxPrecision( precision );\n\n\tif ( maxPrecision !== precision ) {\n\n\t\tconsole.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );\n\t\tprecision = maxPrecision;\n\n\t}\n\n\tvar logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true && !! extensions.get( 'EXT_frag_depth' );\n\n\tvar maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS );\n\tvar maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );\n\tvar maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE );\n\tvar maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE );\n\n\tvar maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );\n\tvar maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS );\n\tvar maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS );\n\tvar maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS );\n\n\tvar vertexTextures = maxVertexTextures > 0;\n\tvar floatFragmentTextures = !! extensions.get( 'OES_texture_float' );\n\tvar floatVertexTextures = vertexTextures && floatFragmentTextures;\n\n\treturn {\n\n\t\tgetMaxAnisotropy: getMaxAnisotropy,\n\t\tgetMaxPrecision: getMaxPrecision,\n\n\t\tprecision: precision,\n\t\tlogarithmicDepthBuffer: logarithmicDepthBuffer,\n\n\t\tmaxTextures: maxTextures,\n\t\tmaxVertexTextures: maxVertexTextures,\n\t\tmaxTextureSize: maxTextureSize,\n\t\tmaxCubemapSize: maxCubemapSize,\n\n\t\tmaxAttributes: maxAttributes,\n\t\tmaxVertexUniforms: maxVertexUniforms,\n\t\tmaxVaryings: maxVaryings,\n\t\tmaxFragmentUniforms: maxFragmentUniforms,\n\n\t\tvertexTextures: vertexTextures,\n\t\tfloatFragmentTextures: floatFragmentTextures,\n\t\tfloatVertexTextures: floatVertexTextures\n\n\t};\n\n}\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction WebGLExtensions( gl ) {\n\n\tvar extensions = {};\n\n\treturn {\n\n\t\tget: function ( name ) {\n\n\t\t\tif ( extensions[ name ] !== undefined ) {\n\n\t\t\t\treturn extensions[ name ];\n\n\t\t\t}\n\n\t\t\tvar extension;\n\n\t\t\tswitch ( name ) {\n\n\t\t\t\tcase 'WEBGL_depth_texture':\n\t\t\t\t\textension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'EXT_texture_filter_anisotropic':\n\t\t\t\t\textension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'WEBGL_compressed_texture_s3tc':\n\t\t\t\t\textension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'WEBGL_compressed_texture_pvrtc':\n\t\t\t\t\textension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'WEBGL_compressed_texture_etc1':\n\t\t\t\t\textension = gl.getExtension( 'WEBGL_compressed_texture_etc1' );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\textension = gl.getExtension( name );\n\n\t\t\t}\n\n\t\t\tif ( extension === null ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );\n\n\t\t\t}\n\n\t\t\textensions[ name ] = extension;\n\n\t\t\treturn extension;\n\n\t\t}\n\n\t};\n\n}\n\n/**\n * @author tschw\n */\n\nfunction WebGLClipping() {\n\n\tvar scope = this,\n\n\t\tglobalState = null,\n\t\tnumGlobalPlanes = 0,\n\t\tlocalClippingEnabled = false,\n\t\trenderingShadows = false,\n\n\t\tplane = new Plane(),\n\t\tviewNormalMatrix = new Matrix3(),\n\n\t\tuniform = { value: null, needsUpdate: false };\n\n\tthis.uniform = uniform;\n\tthis.numPlanes = 0;\n\tthis.numIntersection = 0;\n\n\tthis.init = function( planes, enableLocalClipping, camera ) {\n\n\t\tvar enabled =\n\t\t\tplanes.length !== 0 ||\n\t\t\tenableLocalClipping ||\n\t\t\t// enable state of previous frame - the clipping code has to\n\t\t\t// run another frame in order to reset the state:\n\t\t\tnumGlobalPlanes !== 0 ||\n\t\t\tlocalClippingEnabled;\n\n\t\tlocalClippingEnabled = enableLocalClipping;\n\n\t\tglobalState = projectPlanes( planes, camera, 0 );\n\t\tnumGlobalPlanes = planes.length;\n\n\t\treturn enabled;\n\n\t};\n\n\tthis.beginShadows = function() {\n\n\t\trenderingShadows = true;\n\t\tprojectPlanes( null );\n\n\t};\n\n\tthis.endShadows = function() {\n\n\t\trenderingShadows = false;\n\t\tresetGlobalState();\n\n\t};\n\n\tthis.setState = function( planes, clipIntersection, clipShadows, camera, cache, fromCache ) {\n\n\t\tif ( ! localClippingEnabled ||\n\t\t\t\tplanes === null || planes.length === 0 ||\n\t\t\t\trenderingShadows && ! clipShadows ) {\n\t\t\t// there's no local clipping\n\n\t\t\tif ( renderingShadows ) {\n\t\t\t\t// there's no global clipping\n\n\t\t\t\tprojectPlanes( null );\n\n\t\t\t} else {\n\n\t\t\t\tresetGlobalState();\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tvar nGlobal = renderingShadows ? 0 : numGlobalPlanes,\n\t\t\t\tlGlobal = nGlobal * 4,\n\n\t\t\t\tdstArray = cache.clippingState || null;\n\n\t\t\tuniform.value = dstArray; // ensure unique state\n\n\t\t\tdstArray = projectPlanes( planes, camera, lGlobal, fromCache );\n\n\t\t\tfor ( var i = 0; i !== lGlobal; ++ i ) {\n\n\t\t\t\tdstArray[ i ] = globalState[ i ];\n\n\t\t\t}\n\n\t\t\tcache.clippingState = dstArray;\n\t\t\tthis.numIntersection = clipIntersection ? this.numPlanes : 0;\n\t\t\tthis.numPlanes += nGlobal;\n\n\t\t}\n\n\n\t};\n\n\tfunction resetGlobalState() {\n\n\t\tif ( uniform.value !== globalState ) {\n\n\t\t\tuniform.value = globalState;\n\t\t\tuniform.needsUpdate = numGlobalPlanes > 0;\n\n\t\t}\n\n\t\tscope.numPlanes = numGlobalPlanes;\n\t\tscope.numIntersection = 0;\n\n\t}\n\n\tfunction projectPlanes( planes, camera, dstOffset, skipTransform ) {\n\n\t\tvar nPlanes = planes !== null ? planes.length : 0,\n\t\t\tdstArray = null;\n\n\t\tif ( nPlanes !== 0 ) {\n\n\t\t\tdstArray = uniform.value;\n\n\t\t\tif ( skipTransform !== true || dstArray === null ) {\n\n\t\t\t\tvar flatSize = dstOffset + nPlanes * 4,\n\t\t\t\t\tviewMatrix = camera.matrixWorldInverse;\n\n\t\t\t\tviewNormalMatrix.getNormalMatrix( viewMatrix );\n\n\t\t\t\tif ( dstArray === null || dstArray.length < flatSize ) {\n\n\t\t\t\t\tdstArray = new Float32Array( flatSize );\n\n\t\t\t\t}\n\n\t\t\t\tfor ( var i = 0, i4 = dstOffset;\n\t\t\t\t\t\t\t\t\ti !== nPlanes; ++ i, i4 += 4 ) {\n\n\t\t\t\t\tplane.copy( planes[ i ] ).\n\t\t\t\t\t\t\tapplyMatrix4( viewMatrix, viewNormalMatrix );\n\n\t\t\t\t\tplane.normal.toArray( dstArray, i4 );\n\t\t\t\t\tdstArray[ i4 + 3 ] = plane.constant;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tuniform.value = dstArray;\n\t\t\tuniform.needsUpdate = true;\n\n\t\t}\n\n\t\tscope.numPlanes = nPlanes;\n\t\t\n\t\treturn dstArray;\n\n\t}\n\n}\n\n/**\n * @author supereggbert / http://www.paulbrunt.co.uk/\n * @author mrdoob / http://mrdoob.com/\n * @author alteredq / http://alteredqualia.com/\n * @author szimek / https://github.com/szimek/\n * @author tschw\n */\n\nfunction WebGLRenderer( parameters ) {\n\n\tconsole.log( 'THREE.WebGLRenderer', REVISION );\n\n\tparameters = parameters || {};\n\n\tvar _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ),\n\t\t_context = parameters.context !== undefined ? parameters.context : null,\n\n\t\t_alpha = parameters.alpha !== undefined ? parameters.alpha : false,\n\t\t_depth = parameters.depth !== undefined ? parameters.depth : true,\n\t\t_stencil = parameters.stencil !== undefined ? parameters.stencil : true,\n\t\t_antialias = parameters.antialias !== undefined ? parameters.antialias : false,\n\t\t_premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,\n\t\t_preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false;\n\n\tvar lights = [];\n\n\tvar opaqueObjects = [];\n\tvar opaqueObjectsLastIndex = - 1;\n\tvar transparentObjects = [];\n\tvar transparentObjectsLastIndex = - 1;\n\n\tvar morphInfluences = new Float32Array( 8 );\n\n\tvar sprites = [];\n\tvar lensFlares = [];\n\n\t// public properties\n\n\tthis.domElement = _canvas;\n\tthis.context = null;\n\n\t// clearing\n\n\tthis.autoClear = true;\n\tthis.autoClearColor = true;\n\tthis.autoClearDepth = true;\n\tthis.autoClearStencil = true;\n\n\t// scene graph\n\n\tthis.sortObjects = true;\n\n\t// user-defined clipping\n\n\tthis.clippingPlanes = [];\n\tthis.localClippingEnabled = false;\n\n\t// physically based shading\n\n\tthis.gammaFactor = 2.0;\t// for backwards compatibility\n\tthis.gammaInput = false;\n\tthis.gammaOutput = false;\n\n\t// physical lights\n\n\tthis.physicallyCorrectLights = false;\n\n\t// tone mapping\n\n\tthis.toneMapping = LinearToneMapping;\n\tthis.toneMappingExposure = 1.0;\n\tthis.toneMappingWhitePoint = 1.0;\n\n\t// morphs\n\n\tthis.maxMorphTargets = 8;\n\tthis.maxMorphNormals = 4;\n\n\t// internal properties\n\n\tvar _this = this,\n\n\t\t// internal state cache\n\n\t\t_currentProgram = null,\n\t\t_currentRenderTarget = null,\n\t\t_currentFramebuffer = null,\n\t\t_currentMaterialId = - 1,\n\t\t_currentGeometryProgram = '',\n\t\t_currentCamera = null,\n\n\t\t_currentScissor = new Vector4(),\n\t\t_currentScissorTest = null,\n\n\t\t_currentViewport = new Vector4(),\n\n\t\t//\n\n\t\t_usedTextureUnits = 0,\n\n\t\t//\n\n\t\t_clearColor = new Color( 0x000000 ),\n\t\t_clearAlpha = 0,\n\n\t\t_width = _canvas.width,\n\t\t_height = _canvas.height,\n\n\t\t_pixelRatio = 1,\n\n\t\t_scissor = new Vector4( 0, 0, _width, _height ),\n\t\t_scissorTest = false,\n\n\t\t_viewport = new Vector4( 0, 0, _width, _height ),\n\n\t\t// frustum\n\n\t\t_frustum = new Frustum(),\n\n\t\t// clipping\n\n\t\t_clipping = new WebGLClipping(),\n\t\t_clippingEnabled = false,\n\t\t_localClippingEnabled = false,\n\n\t\t_sphere = new Sphere(),\n\n\t\t// camera matrices cache\n\n\t\t_projScreenMatrix = new Matrix4(),\n\n\t\t_vector3 = new Vector3(),\n\t\t_matrix4 = new Matrix4(),\n\t\t_matrix42 = new Matrix4(),\n\n\t\t// light arrays cache\n\n\t\t_lights = {\n\n\t\t\thash: '',\n\n\t\tambient: [ 0, 0, 0 ],\n\t\tdirectional: [],\n\t\tdirectionalShadowMap: [],\n\t\tdirectionalShadowMatrix: [],\n\t\tspot: [],\n\t\tspotShadowMap: [],\n\t\tspotShadowMatrix: [],\n\t\trectArea: [],\n\t\tpoint: [],\n\t\tpointShadowMap: [],\n\t\tpointShadowMatrix: [],\n\t\themi: [],\n\n\t\t\tshadows: []\n\n\t\t},\n\n\t\t// info\n\n\t\t_infoRender = {\n\n\t\t\tcalls: 0,\n\t\t\tvertices: 0,\n\t\t\tfaces: 0,\n\t\t\tpoints: 0\n\n\t\t};\n\n\tthis.info = {\n\n\t\trender: _infoRender,\n\t\tmemory: {\n\n\t\t\tgeometries: 0,\n\t\t\ttextures: 0\n\n\t\t},\n\t\tprograms: null\n\n\t};\n\n\n\t// initialize\n\n\tvar _gl;\n\n\ttry {\n\n\t\tvar attributes = {\n\t\t\talpha: _alpha,\n\t\t\tdepth: _depth,\n\t\t\tstencil: _stencil,\n\t\t\tantialias: _antialias,\n\t\t\tpremultipliedAlpha: _premultipliedAlpha,\n\t\t\tpreserveDrawingBuffer: _preserveDrawingBuffer\n\t\t};\n\n\t\t_gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes );\n\n\t\tif ( _gl === null ) {\n\n\t\t\tif ( _canvas.getContext( 'webgl' ) !== null ) {\n\n\t\t\t\tthrow 'Error creating WebGL context with your selected attributes.';\n\n\t\t\t} else {\n\n\t\t\t\tthrow 'Error creating WebGL context.';\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Some experimental-webgl implementations do not have getShaderPrecisionFormat\n\n\t\tif ( _gl.getShaderPrecisionFormat === undefined ) {\n\n\t\t\t_gl.getShaderPrecisionFormat = function () {\n\n\t\t\t\treturn { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };\n\n\t\t\t};\n\n\t\t}\n\n\t\t_canvas.addEventListener( 'webglcontextlost', onContextLost, false );\n\n\t} catch ( error ) {\n\n\t\tconsole.error( 'THREE.WebGLRenderer: ' + error );\n\n\t}\n\n\tvar extensions = new WebGLExtensions( _gl );\n\n\textensions.get( 'WEBGL_depth_texture' );\n\textensions.get( 'OES_texture_float' );\n\textensions.get( 'OES_texture_float_linear' );\n\textensions.get( 'OES_texture_half_float' );\n\textensions.get( 'OES_texture_half_float_linear' );\n\textensions.get( 'OES_standard_derivatives' );\n\textensions.get( 'ANGLE_instanced_arrays' );\n\n\tif ( extensions.get( 'OES_element_index_uint' ) ) {\n\n\t\tBufferGeometry.MaxIndex = 4294967296;\n\n\t}\n\n\tvar capabilities = new WebGLCapabilities( _gl, extensions, parameters );\n\n\tvar state = new WebGLState( _gl, extensions, paramThreeToGL );\n\tvar properties = new WebGLProperties();\n\tvar textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, this.info );\n\tvar objects = new WebGLObjects( _gl, properties, this.info );\n\tvar programCache = new WebGLPrograms( this, capabilities );\n\tvar lightCache = new WebGLLights();\n\n\tthis.info.programs = programCache.programs;\n\n\tvar bufferRenderer = new WebGLBufferRenderer( _gl, extensions, _infoRender );\n\tvar indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, _infoRender );\n\n\t//\n\n\tvar backgroundPlaneCamera, backgroundPlaneMesh;\n\tvar backgroundBoxCamera, backgroundBoxMesh;\n\n\t//\n\n\tfunction getTargetPixelRatio() {\n\n\t\treturn _currentRenderTarget === null ? _pixelRatio : 1;\n\n\t}\n\n\tfunction setDefaultGLState() {\n\n\t\tstate.init();\n\n\t\tstate.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) );\n\t\tstate.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) );\n\n\t\tstate.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha );\n\n\t}\n\n\tfunction resetGLState() {\n\n\t\t_currentProgram = null;\n\t\t_currentCamera = null;\n\n\t\t_currentGeometryProgram = '';\n\t\t_currentMaterialId = - 1;\n\n\t\tstate.reset();\n\n\t}\n\n\tsetDefaultGLState();\n\n\tthis.context = _gl;\n\tthis.capabilities = capabilities;\n\tthis.extensions = extensions;\n\tthis.properties = properties;\n\tthis.state = state;\n\n\t// shadow map\n\n\tvar shadowMap = new WebGLShadowMap( this, _lights, objects, capabilities );\n\n\tthis.shadowMap = shadowMap;\n\n\n\t// Plugins\n\n\tvar spritePlugin = new SpritePlugin( this, sprites );\n\tvar lensFlarePlugin = new LensFlarePlugin( this, lensFlares );\n\n\t// API\n\n\tthis.getContext = function () {\n\n\t\treturn _gl;\n\n\t};\n\n\tthis.getContextAttributes = function () {\n\n\t\treturn _gl.getContextAttributes();\n\n\t};\n\n\tthis.forceContextLoss = function () {\n\n\t\textensions.get( 'WEBGL_lose_context' ).loseContext();\n\n\t};\n\n\tthis.getMaxAnisotropy = function () {\n\n\t\treturn capabilities.getMaxAnisotropy();\n\n\t};\n\n\tthis.getPrecision = function () {\n\n\t\treturn capabilities.precision;\n\n\t};\n\n\tthis.getPixelRatio = function () {\n\n\t\treturn _pixelRatio;\n\n\t};\n\n\tthis.setPixelRatio = function ( value ) {\n\n\t\tif ( value === undefined ) return;\n\n\t\t_pixelRatio = value;\n\n\t\tthis.setSize( _viewport.z, _viewport.w, false );\n\n\t};\n\n\tthis.getSize = function () {\n\n\t\treturn {\n\t\t\twidth: _width,\n\t\t\theight: _height\n\t\t};\n\n\t};\n\n\tthis.setSize = function ( width, height, updateStyle ) {\n\n\t\t_width = width;\n\t\t_height = height;\n\n\t\t_canvas.width = width * _pixelRatio;\n\t\t_canvas.height = height * _pixelRatio;\n\n\t\tif ( updateStyle !== false ) {\n\n\t\t\t_canvas.style.width = width + 'px';\n\t\t\t_canvas.style.height = height + 'px';\n\n\t\t}\n\n\t\tthis.setViewport( 0, 0, width, height );\n\n\t};\n\n\tthis.setViewport = function ( x, y, width, height ) {\n\n\t\tstate.viewport( _viewport.set( x, y, width, height ) );\n\n\t};\n\n\tthis.setScissor = function ( x, y, width, height ) {\n\n\t\tstate.scissor( _scissor.set( x, y, width, height ) );\n\n\t};\n\n\tthis.setScissorTest = function ( boolean ) {\n\n\t\tstate.setScissorTest( _scissorTest = boolean );\n\n\t};\n\n\t// Clearing\n\n\tthis.getClearColor = function () {\n\n\t\treturn _clearColor;\n\n\t};\n\n\tthis.setClearColor = function ( color, alpha ) {\n\n\t\t_clearColor.set( color );\n\n\t\t_clearAlpha = alpha !== undefined ? alpha : 1;\n\n\t\tstate.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha );\n\n\t};\n\n\tthis.getClearAlpha = function () {\n\n\t\treturn _clearAlpha;\n\n\t};\n\n\tthis.setClearAlpha = function ( alpha ) {\n\n\t\t_clearAlpha = alpha;\n\n\t\tstate.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha );\n\n\t};\n\n\tthis.clear = function ( color, depth, stencil ) {\n\n\t\tvar bits = 0;\n\n\t\tif ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT;\n\t\tif ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT;\n\t\tif ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT;\n\n\t\t_gl.clear( bits );\n\n\t};\n\n\tthis.clearColor = function () {\n\n\t\tthis.clear( true, false, false );\n\n\t};\n\n\tthis.clearDepth = function () {\n\n\t\tthis.clear( false, true, false );\n\n\t};\n\n\tthis.clearStencil = function () {\n\n\t\tthis.clear( false, false, true );\n\n\t};\n\n\tthis.clearTarget = function ( renderTarget, color, depth, stencil ) {\n\n\t\tthis.setRenderTarget( renderTarget );\n\t\tthis.clear( color, depth, stencil );\n\n\t};\n\n\t// Reset\n\n\tthis.resetGLState = resetGLState;\n\n\tthis.dispose = function() {\n\n\t\ttransparentObjects = [];\n\t\ttransparentObjectsLastIndex = -1;\n\t\topaqueObjects = [];\n\t\topaqueObjectsLastIndex = -1;\n\n\t\t_canvas.removeEventListener( 'webglcontextlost', onContextLost, false );\n\n\t};\n\n\t// Events\n\n\tfunction onContextLost( event ) {\n\n\t\tevent.preventDefault();\n\n\t\tresetGLState();\n\t\tsetDefaultGLState();\n\n\t\tproperties.clear();\n\n\t}\n\n\tfunction onMaterialDispose( event ) {\n\n\t\tvar material = event.target;\n\n\t\tmaterial.removeEventListener( 'dispose', onMaterialDispose );\n\n\t\tdeallocateMaterial( material );\n\n\t}\n\n\t// Buffer deallocation\n\n\tfunction deallocateMaterial( material ) {\n\n\t\treleaseMaterialProgramReference( material );\n\n\t\tproperties.delete( material );\n\n\t}\n\n\n\tfunction releaseMaterialProgramReference( material ) {\n\n\t\tvar programInfo = properties.get( material ).program;\n\n\t\tmaterial.program = undefined;\n\n\t\tif ( programInfo !== undefined ) {\n\n\t\t\tprogramCache.releaseProgram( programInfo );\n\n\t\t}\n\n\t}\n\n\t// Buffer rendering\n\n\tthis.renderBufferImmediate = function ( object, program, material ) {\n\n\t\tstate.initAttributes();\n\n\t\tvar buffers = properties.get( object );\n\n\t\tif ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer();\n\t\tif ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer();\n\t\tif ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer();\n\t\tif ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer();\n\n\t\tvar attributes = program.getAttributes();\n\n\t\tif ( object.hasPositions ) {\n\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.position );\n\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );\n\n\t\t\tstate.enableAttribute( attributes.position );\n\t\t\t_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );\n\n\t\t}\n\n\t\tif ( object.hasNormals ) {\n\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.normal );\n\n\t\t\tif ( ! material.isMeshPhongMaterial &&\n\t\t\t\t! material.isMeshStandardMaterial &&\n\t\t\t\t! material.isMeshNormalMaterial &&\n\t\t\t\tmaterial.shading === FlatShading ) {\n\n\t\t\t\tfor ( var i = 0, l = object.count * 3; i < l; i += 9 ) {\n\n\t\t\t\t\tvar array = object.normalArray;\n\n\t\t\t\t\tvar nx = ( array[ i + 0 ] + array[ i + 3 ] + array[ i + 6 ] ) / 3;\n\t\t\t\t\tvar ny = ( array[ i + 1 ] + array[ i + 4 ] + array[ i + 7 ] ) / 3;\n\t\t\t\t\tvar nz = ( array[ i + 2 ] + array[ i + 5 ] + array[ i + 8 ] ) / 3;\n\n\t\t\t\t\tarray[ i + 0 ] = nx;\n\t\t\t\t\tarray[ i + 1 ] = ny;\n\t\t\t\t\tarray[ i + 2 ] = nz;\n\n\t\t\t\t\tarray[ i + 3 ] = nx;\n\t\t\t\t\tarray[ i + 4 ] = ny;\n\t\t\t\t\tarray[ i + 5 ] = nz;\n\n\t\t\t\t\tarray[ i + 6 ] = nx;\n\t\t\t\t\tarray[ i + 7 ] = ny;\n\t\t\t\t\tarray[ i + 8 ] = nz;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );\n\n\t\t\tstate.enableAttribute( attributes.normal );\n\n\t\t\t_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );\n\n\t\t}\n\n\t\tif ( object.hasUvs && material.map ) {\n\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.uv );\n\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );\n\n\t\t\tstate.enableAttribute( attributes.uv );\n\n\t\t\t_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );\n\n\t\t}\n\n\t\tif ( object.hasColors && material.vertexColors !== NoColors ) {\n\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.color );\n\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );\n\n\t\t\tstate.enableAttribute( attributes.color );\n\n\t\t\t_gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 );\n\n\t\t}\n\n\t\tstate.disableUnusedAttributes();\n\n\t\t_gl.drawArrays( _gl.TRIANGLES, 0, object.count );\n\n\t\tobject.count = 0;\n\n\t};\n\n\tthis.renderBufferDirect = function ( camera, fog, geometry, material, object, group ) {\n\n\t\tsetMaterial( material );\n\n\t\tvar program = setProgram( camera, fog, material, object );\n\n\t\tvar updateBuffers = false;\n\t\tvar geometryProgram = geometry.id + '_' + program.id + '_' + material.wireframe;\n\n\t\tif ( geometryProgram !== _currentGeometryProgram ) {\n\n\t\t\t_currentGeometryProgram = geometryProgram;\n\t\t\tupdateBuffers = true;\n\n\t\t}\n\n\t\t// morph targets\n\n\t\tvar morphTargetInfluences = object.morphTargetInfluences;\n\n\t\tif ( morphTargetInfluences !== undefined ) {\n\n\t\t\tvar activeInfluences = [];\n\n\t\t\tfor ( var i = 0, l = morphTargetInfluences.length; i < l; i ++ ) {\n\n\t\t\t\tvar influence = morphTargetInfluences[ i ];\n\t\t\t\tactiveInfluences.push( [ influence, i ] );\n\n\t\t\t}\n\n\t\t\tactiveInfluences.sort( absNumericalSort );\n\n\t\t\tif ( activeInfluences.length > 8 ) {\n\n\t\t\t\tactiveInfluences.length = 8;\n\n\t\t\t}\n\n\t\t\tvar morphAttributes = geometry.morphAttributes;\n\n\t\t\tfor ( var i = 0, l = activeInfluences.length; i < l; i ++ ) {\n\n\t\t\t\tvar influence = activeInfluences[ i ];\n\t\t\t\tmorphInfluences[ i ] = influence[ 0 ];\n\n\t\t\t\tif ( influence[ 0 ] !== 0 ) {\n\n\t\t\t\t\tvar index = influence[ 1 ];\n\n\t\t\t\t\tif ( material.morphTargets === true && morphAttributes.position ) geometry.addAttribute( 'morphTarget' + i, morphAttributes.position[ index ] );\n\t\t\t\t\tif ( material.morphNormals === true && morphAttributes.normal ) geometry.addAttribute( 'morphNormal' + i, morphAttributes.normal[ index ] );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( material.morphTargets === true ) geometry.removeAttribute( 'morphTarget' + i );\n\t\t\t\t\tif ( material.morphNormals === true ) geometry.removeAttribute( 'morphNormal' + i );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tfor ( var i = activeInfluences.length, il = morphInfluences.length; i < il; i ++ ) {\n\n\t\t\t\tmorphInfluences[ i ] = 0.0;\n\n\t\t\t}\n\n\t\t\tprogram.getUniforms().setValue(\n\t\t\t\t_gl, 'morphTargetInfluences', morphInfluences );\n\n\t\t\tupdateBuffers = true;\n\n\t\t}\n\n\t\t//\n\n\t\tvar index = geometry.index;\n\t\tvar position = geometry.attributes.position;\n\t\tvar rangeFactor = 1;\n\n\t\tif ( material.wireframe === true ) {\n\n\t\t\tindex = objects.getWireframeAttribute( geometry );\n\t\t\trangeFactor = 2;\n\n\t\t}\n\n\t\tvar renderer;\n\n\t\tif ( index !== null ) {\n\n\t\t\trenderer = indexedBufferRenderer;\n\t\t\trenderer.setIndex( index );\n\n\t\t} else {\n\n\t\t\trenderer = bufferRenderer;\n\n\t\t}\n\n\t\tif ( updateBuffers ) {\n\n\t\t\tsetupVertexAttributes( material, program, geometry );\n\n\t\t\tif ( index !== null ) {\n\n\t\t\t\t_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, objects.getAttributeBuffer( index ) );\n\n\t\t\t}\n\n\t\t}\n\n\t\t//\n\n\t\tvar dataCount = 0;\n\n\t\tif ( index !== null ) {\n\n\t\t\tdataCount = index.count;\n\n\t\t} else if ( position !== undefined ) {\n\n\t\t\tdataCount = position.count;\n\n\t\t}\n\n\t\tvar rangeStart = geometry.drawRange.start * rangeFactor;\n\t\tvar rangeCount = geometry.drawRange.count * rangeFactor;\n\n\t\tvar groupStart = group !== null ? group.start * rangeFactor : 0;\n\t\tvar groupCount = group !== null ? group.count * rangeFactor : Infinity;\n\n\t\tvar drawStart = Math.max( rangeStart, groupStart );\n\t\tvar drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1;\n\n\t\tvar drawCount = Math.max( 0, drawEnd - drawStart + 1 );\n\n\t\tif ( drawCount === 0 ) return;\n\n\t\t//\n\n\t\tif ( object.isMesh ) {\n\n\t\t\tif ( material.wireframe === true ) {\n\n\t\t\t\tstate.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );\n\t\t\t\trenderer.setMode( _gl.LINES );\n\n\t\t\t} else {\n\n\t\t\t\tswitch ( object.drawMode ) {\n\n\t\t\t\t\tcase TrianglesDrawMode:\n\t\t\t\t\t\trenderer.setMode( _gl.TRIANGLES );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase TriangleStripDrawMode:\n\t\t\t\t\t\trenderer.setMode( _gl.TRIANGLE_STRIP );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase TriangleFanDrawMode:\n\t\t\t\t\t\trenderer.setMode( _gl.TRIANGLE_FAN );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\n\t\t} else if ( object.isLine ) {\n\n\t\t\tvar lineWidth = material.linewidth;\n\n\t\t\tif ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material\n\n\t\t\tstate.setLineWidth( lineWidth * getTargetPixelRatio() );\n\n\t\t\tif ( object.isLineSegments ) {\n\n\t\t\t\trenderer.setMode( _gl.LINES );\n\n\t\t\t} else {\n\n\t\t\t\trenderer.setMode( _gl.LINE_STRIP );\n\n\t\t\t}\n\n\t\t} else if ( object.isPoints ) {\n\n\t\t\trenderer.setMode( _gl.POINTS );\n\n\t\t}\n\n\t\tif ( geometry && geometry.isInstancedBufferGeometry ) {\n\n\t\t\tif ( geometry.maxInstancedCount > 0 ) {\n\n\t\t\t\trenderer.renderInstances( geometry, drawStart, drawCount );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\trenderer.render( drawStart, drawCount );\n\n\t\t}\n\n\t};\n\n\tfunction setupVertexAttributes( material, program, geometry, startIndex ) {\n\n\t\tvar extension;\n\n\t\tif ( geometry && geometry.isInstancedBufferGeometry ) {\n\n\t\t\textension = extensions.get( 'ANGLE_instanced_arrays' );\n\n\t\t\tif ( extension === null ) {\n\n\t\t\t\tconsole.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( startIndex === undefined ) startIndex = 0;\n\n\t\tstate.initAttributes();\n\n\t\tvar geometryAttributes = geometry.attributes;\n\n\t\tvar programAttributes = program.getAttributes();\n\n\t\tvar materialDefaultAttributeValues = material.defaultAttributeValues;\n\n\t\tfor ( var name in programAttributes ) {\n\n\t\t\tvar programAttribute = programAttributes[ name ];\n\n\t\t\tif ( programAttribute >= 0 ) {\n\n\t\t\t\tvar geometryAttribute = geometryAttributes[ name ];\n\n\t\t\t\tif ( geometryAttribute !== undefined ) {\n\n\t\t\t\t\tvar normalized = geometryAttribute.normalized;\n\t\t\t\t\tvar size = geometryAttribute.itemSize;\n\n\t\t\t\t\tvar attributeProperties = objects.getAttributeProperties( geometryAttribute );\n\n\t\t\t\t\tvar buffer = attributeProperties.__webglBuffer;\n\t\t\t\t\tvar type = attributeProperties.type;\n\t\t\t\t\tvar bytesPerElement = attributeProperties.bytesPerElement;\n\n\t\t\t\t\tif ( geometryAttribute.isInterleavedBufferAttribute ) {\n\n\t\t\t\t\t\tvar data = geometryAttribute.data;\n\t\t\t\t\t\tvar stride = data.stride;\n\t\t\t\t\t\tvar offset = geometryAttribute.offset;\n\n\t\t\t\t\t\tif ( data && data.isInstancedInterleavedBuffer ) {\n\n\t\t\t\t\t\t\tstate.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute, extension );\n\n\t\t\t\t\t\t\tif ( geometry.maxInstancedCount === undefined ) {\n\n\t\t\t\t\t\t\t\tgeometry.maxInstancedCount = data.meshPerAttribute * data.count;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tstate.enableAttribute( programAttribute );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );\n\t\t\t\t\t\t_gl.vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, ( startIndex * stride + offset ) * bytesPerElement );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( geometryAttribute.isInstancedBufferAttribute ) {\n\n\t\t\t\t\t\t\tstate.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute, extension );\n\n\t\t\t\t\t\t\tif ( geometry.maxInstancedCount === undefined ) {\n\n\t\t\t\t\t\t\t\tgeometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tstate.enableAttribute( programAttribute );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );\n\t\t\t\t\t\t_gl.vertexAttribPointer( programAttribute, size, type, normalized, 0, startIndex * size * bytesPerElement );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( materialDefaultAttributeValues !== undefined ) {\n\n\t\t\t\t\tvar value = materialDefaultAttributeValues[ name ];\n\n\t\t\t\t\tif ( value !== undefined ) {\n\n\t\t\t\t\t\tswitch ( value.length ) {\n\n\t\t\t\t\t\t\tcase 2:\n\t\t\t\t\t\t\t\t_gl.vertexAttrib2fv( programAttribute, value );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase 3:\n\t\t\t\t\t\t\t\t_gl.vertexAttrib3fv( programAttribute, value );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase 4:\n\t\t\t\t\t\t\t\t_gl.vertexAttrib4fv( programAttribute, value );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t_gl.vertexAttrib1fv( programAttribute, value );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tstate.disableUnusedAttributes();\n\n\t}\n\n\t// Sorting\n\n\tfunction absNumericalSort( a, b ) {\n\n\t\treturn Math.abs( b[ 0 ] ) - Math.abs( a[ 0 ] );\n\n\t}\n\n\tfunction painterSortStable( a, b ) {\n\n\t\tif ( a.object.renderOrder !== b.object.renderOrder ) {\n\n\t\t\treturn a.object.renderOrder - b.object.renderOrder;\n\n\t\t} else if ( a.material.program && b.material.program && a.material.program !== b.material.program ) {\n\n\t\t\treturn a.material.program.id - b.material.program.id;\n\n\t\t} else if ( a.material.id !== b.material.id ) {\n\n\t\t\treturn a.material.id - b.material.id;\n\n\t\t} else if ( a.z !== b.z ) {\n\n\t\t\treturn a.z - b.z;\n\n\t\t} else {\n\n\t\t\treturn a.id - b.id;\n\n\t\t}\n\n\t}\n\n\tfunction reversePainterSortStable( a, b ) {\n\n\t\tif ( a.object.renderOrder !== b.object.renderOrder ) {\n\n\t\t\treturn a.object.renderOrder - b.object.renderOrder;\n\n\t\t} if ( a.z !== b.z ) {\n\n\t\t\treturn b.z - a.z;\n\n\t\t} else {\n\n\t\t\treturn a.id - b.id;\n\n\t\t}\n\n\t}\n\n\t// Rendering\n\n\tthis.render = function ( scene, camera, renderTarget, forceClear ) {\n\n\t\tif ( camera !== undefined && camera.isCamera !== true ) {\n\n\t\t\tconsole.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\t// reset caching for this frame\n\n\t\t_currentGeometryProgram = '';\n\t\t_currentMaterialId = - 1;\n\t\t_currentCamera = null;\n\n\t\t// update scene graph\n\n\t\tif ( scene.autoUpdate === true ) scene.updateMatrixWorld();\n\n\t\t// update camera matrices and frustum\n\n\t\tif ( camera.parent === null ) camera.updateMatrixWorld();\n\n\t\tcamera.matrixWorldInverse.getInverse( camera.matrixWorld );\n\n\t\t_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );\n\t\t_frustum.setFromMatrix( _projScreenMatrix );\n\n\t\tlights.length = 0;\n\n\t\topaqueObjectsLastIndex = - 1;\n\t\ttransparentObjectsLastIndex = - 1;\n\n\t\tsprites.length = 0;\n\t\tlensFlares.length = 0;\n\n\t\t_localClippingEnabled = this.localClippingEnabled;\n\t\t_clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera );\n\n\t\tprojectObject( scene, camera );\n\n\t\topaqueObjects.length = opaqueObjectsLastIndex + 1;\n\t\ttransparentObjects.length = transparentObjectsLastIndex + 1;\n\n\t\tif ( _this.sortObjects === true ) {\n\n\t\t\topaqueObjects.sort( painterSortStable );\n\t\t\ttransparentObjects.sort( reversePainterSortStable );\n\n\t\t}\n\n\t\t//\n\n\t\tif ( _clippingEnabled ) _clipping.beginShadows();\n\n\t\tsetupShadows( lights );\n\n\t\tshadowMap.render( scene, camera );\n\n\t\tsetupLights( lights, camera );\n\n\t\tif ( _clippingEnabled ) _clipping.endShadows();\n\n\t\t//\n\n\t\t_infoRender.calls = 0;\n\t\t_infoRender.vertices = 0;\n\t\t_infoRender.faces = 0;\n\t\t_infoRender.points = 0;\n\n\t\tif ( renderTarget === undefined ) {\n\n\t\t\trenderTarget = null;\n\n\t\t}\n\n\t\tthis.setRenderTarget( renderTarget );\n\n\t\t//\n\n\t\tvar background = scene.background;\n\n\t\tif ( background === null ) {\n\n\t\t\tstate.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha );\n\n\t\t} else if ( background && background.isColor ) {\n\n\t\t\tstate.buffers.color.setClear( background.r, background.g, background.b, 1, _premultipliedAlpha );\n\t\t\tforceClear = true;\n\n\t\t}\n\n\t\tif ( this.autoClear || forceClear ) {\n\n\t\t\tthis.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil );\n\n\t\t}\n\n\t\tif ( background && background.isCubeTexture ) {\n\n\t\t\tif ( backgroundBoxCamera === undefined ) {\n\n\t\t\t\tbackgroundBoxCamera = new PerspectiveCamera();\n\n\t\t\t\tbackgroundBoxMesh = new Mesh(\n\t\t\t\t\tnew BoxBufferGeometry( 5, 5, 5 ),\n\t\t\t\t\tnew ShaderMaterial( {\n\t\t\t\t\t\tuniforms: ShaderLib.cube.uniforms,\n\t\t\t\t\t\tvertexShader: ShaderLib.cube.vertexShader,\n\t\t\t\t\t\tfragmentShader: ShaderLib.cube.fragmentShader,\n\t\t\t\t\t\tside: BackSide,\n\t\t\t\t\t\tdepthTest: false,\n\t\t\t\t\t\tdepthWrite: false,\n\t\t\t\t\t\tfog: false\n\t\t\t\t\t} )\n\t\t\t\t);\n\n\t\t\t}\n\n\t\t\tbackgroundBoxCamera.projectionMatrix.copy( camera.projectionMatrix );\n\n\t\t\tbackgroundBoxCamera.matrixWorld.extractRotation( camera.matrixWorld );\n\t\t\tbackgroundBoxCamera.matrixWorldInverse.getInverse( backgroundBoxCamera.matrixWorld );\n\n\n\t\t\tbackgroundBoxMesh.material.uniforms[ \"tCube\" ].value = background;\n\t\t\tbackgroundBoxMesh.modelViewMatrix.multiplyMatrices( backgroundBoxCamera.matrixWorldInverse, backgroundBoxMesh.matrixWorld );\n\n\t\t\tobjects.update( backgroundBoxMesh );\n\n\t\t\t_this.renderBufferDirect( backgroundBoxCamera, null, backgroundBoxMesh.geometry, backgroundBoxMesh.material, backgroundBoxMesh, null );\n\n\t\t} else if ( background && background.isTexture ) {\n\n\t\t\tif ( backgroundPlaneCamera === undefined ) {\n\n\t\t\t\tbackgroundPlaneCamera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );\n\n\t\t\t\tbackgroundPlaneMesh = new Mesh(\n\t\t\t\t\tnew PlaneBufferGeometry( 2, 2 ),\n\t\t\t\t\tnew MeshBasicMaterial( { depthTest: false, depthWrite: false, fog: false } )\n\t\t\t\t);\n\n\t\t\t}\n\n\t\t\tbackgroundPlaneMesh.material.map = background;\n\n\t\t\tobjects.update( backgroundPlaneMesh );\n\n\t\t\t_this.renderBufferDirect( backgroundPlaneCamera, null, backgroundPlaneMesh.geometry, backgroundPlaneMesh.material, backgroundPlaneMesh, null );\n\n\t\t}\n\n\t\t//\n\n\t\tif ( scene.overrideMaterial ) {\n\n\t\t\tvar overrideMaterial = scene.overrideMaterial;\n\n\t\t\trenderObjects( opaqueObjects, scene, camera, overrideMaterial );\n\t\t\trenderObjects( transparentObjects, scene, camera, overrideMaterial );\n\n\t\t} else {\n\n\t\t\t// opaque pass (front-to-back order)\n\n\t\t\tstate.setBlending( NoBlending );\n\t\t\trenderObjects( opaqueObjects, scene, camera );\n\n\t\t\t// transparent pass (back-to-front order)\n\n\t\t\trenderObjects( transparentObjects, scene, camera );\n\n\t\t}\n\n\t\t// custom render plugins (post pass)\n\n\t\tspritePlugin.render( scene, camera );\n\t\tlensFlarePlugin.render( scene, camera, _currentViewport );\n\n\t\t// Generate mipmap if we're using any kind of mipmap filtering\n\n\t\tif ( renderTarget ) {\n\n\t\t\ttextures.updateRenderTargetMipmap( renderTarget );\n\n\t\t}\n\n\t\t// Ensure depth buffer writing is enabled so it can be cleared on next render\n\n\t\tstate.setDepthTest( true );\n\t\tstate.setDepthWrite( true );\n\t\tstate.setColorWrite( true );\n\n\t\t// _gl.finish();\n\n\t};\n\n\tfunction pushRenderItem( object, geometry, material, z, group ) {\n\n\t\tvar array, index;\n\n\t\t// allocate the next position in the appropriate array\n\n\t\tif ( material.transparent ) {\n\n\t\t\tarray = transparentObjects;\n\t\t\tindex = ++ transparentObjectsLastIndex;\n\n\t\t} else {\n\n\t\t\tarray = opaqueObjects;\n\t\t\tindex = ++ opaqueObjectsLastIndex;\n\n\t\t}\n\n\t\t// recycle existing render item or grow the array\n\n\t\tvar renderItem = array[ index ];\n\n\t\tif ( renderItem !== undefined ) {\n\n\t\t\trenderItem.id = object.id;\n\t\t\trenderItem.object = object;\n\t\t\trenderItem.geometry = geometry;\n\t\t\trenderItem.material = material;\n\t\t\trenderItem.z = _vector3.z;\n\t\t\trenderItem.group = group;\n\n\t\t} else {\n\n\t\t\trenderItem = {\n\t\t\t\tid: object.id,\n\t\t\t\tobject: object,\n\t\t\t\tgeometry: geometry,\n\t\t\t\tmaterial: material,\n\t\t\t\tz: _vector3.z,\n\t\t\t\tgroup: group\n\t\t\t};\n\n\t\t\t// assert( index === array.length );\n\t\t\tarray.push( renderItem );\n\n\t\t}\n\n\t}\n\n\t// TODO Duplicated code (Frustum)\n\n\tfunction isObjectViewable( object ) {\n\n\t\tvar geometry = object.geometry;\n\n\t\tif ( geometry.boundingSphere === null )\n\t\t\tgeometry.computeBoundingSphere();\n\n\t\t_sphere.copy( geometry.boundingSphere ).\n\t\tapplyMatrix4( object.matrixWorld );\n\n\t\treturn isSphereViewable( _sphere );\n\n\t}\n\n\tfunction isSpriteViewable( sprite ) {\n\n\t\t_sphere.center.set( 0, 0, 0 );\n\t\t_sphere.radius = 0.7071067811865476;\n\t\t_sphere.applyMatrix4( sprite.matrixWorld );\n\n\t\treturn isSphereViewable( _sphere );\n\n\t}\n\n\tfunction isSphereViewable( sphere ) {\n\n\t\tif ( ! _frustum.intersectsSphere( sphere ) ) return false;\n\n\t\tvar numPlanes = _clipping.numPlanes;\n\n\t\tif ( numPlanes === 0 ) return true;\n\n\t\tvar planes = _this.clippingPlanes,\n\n\t\t\tcenter = sphere.center,\n\t\t\tnegRad = - sphere.radius,\n\t\t\ti = 0;\n\n\t\tdo {\n\n\t\t\t// out when deeper than radius in the negative halfspace\n\t\t\tif ( planes[ i ].distanceToPoint( center ) < negRad ) return false;\n\n\t\t} while ( ++ i !== numPlanes );\n\n\t\treturn true;\n\n\t}\n\n\tfunction projectObject( object, camera ) {\n\n\t\tif ( object.visible === false ) return;\n\n\t\tvar visible = ( object.layers.mask & camera.layers.mask ) !== 0;\n\n\t\tif ( visible ) {\n\n\t\t\tif ( object.isLight ) {\n\n\t\t\t\tlights.push( object );\n\n\t\t\t} else if ( object.isSprite ) {\n\n\t\t\t\tif ( object.frustumCulled === false || isSpriteViewable( object ) === true ) {\n\n\t\t\t\t\tsprites.push( object );\n\n\t\t\t\t}\n\n\t\t\t} else if ( object.isLensFlare ) {\n\n\t\t\t\tlensFlares.push( object );\n\n\t\t\t} else if ( object.isImmediateRenderObject ) {\n\n\t\t\t\tif ( _this.sortObjects === true ) {\n\n\t\t\t\t\t_vector3.setFromMatrixPosition( object.matrixWorld );\n\t\t\t\t\t_vector3.applyMatrix4( _projScreenMatrix );\n\n\t\t\t\t}\n\n\t\t\t\tpushRenderItem( object, null, object.material, _vector3.z, null );\n\n\t\t\t} else if ( object.isMesh || object.isLine || object.isPoints ) {\n\n\t\t\t\tif ( object.isSkinnedMesh ) {\n\n\t\t\t\t\tobject.skeleton.update();\n\n\t\t\t\t}\n\n\t\t\t\tif ( object.frustumCulled === false || isObjectViewable( object ) === true ) {\n\n\t\t\t\t\tvar material = object.material;\n\n\t\t\t\t\tif ( material.visible === true ) {\n\n\t\t\t\t\t\tif ( _this.sortObjects === true ) {\n\n\t\t\t\t\t\t\t_vector3.setFromMatrixPosition( object.matrixWorld );\n\t\t\t\t\t\t\t_vector3.applyMatrix4( _projScreenMatrix );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar geometry = objects.update( object );\n\n\t\t\t\t\t\tif ( material.isMultiMaterial ) {\n\n\t\t\t\t\t\t\tvar groups = geometry.groups;\n\t\t\t\t\t\t\tvar materials = material.materials;\n\n\t\t\t\t\t\t\tfor ( var i = 0, l = groups.length; i < l; i ++ ) {\n\n\t\t\t\t\t\t\t\tvar group = groups[ i ];\n\t\t\t\t\t\t\t\tvar groupMaterial = materials[ group.materialIndex ];\n\n\t\t\t\t\t\t\t\tif ( groupMaterial.visible === true ) {\n\n\t\t\t\t\t\t\t\t\tpushRenderItem( object, geometry, groupMaterial, _vector3.z, group );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tpushRenderItem( object, geometry, material, _vector3.z, null );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar children = object.children;\n\n\t\tfor ( var i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tprojectObject( children[ i ], camera );\n\n\t\t}\n\n\t}\n\n\tfunction renderObjects( renderList, scene, camera, overrideMaterial ) {\n\n\t\tfor ( var i = 0, l = renderList.length; i < l; i ++ ) {\n\n\t\t\tvar renderItem = renderList[ i ];\n\n\t\t\tvar object = renderItem.object;\n\t\t\tvar geometry = renderItem.geometry;\n\t\t\tvar material = overrideMaterial === undefined ? renderItem.material : overrideMaterial;\n\t\t\tvar group = renderItem.group;\n\n\t\t\tobject.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );\n\t\t\tobject.normalMatrix.getNormalMatrix( object.modelViewMatrix );\n\n\t\t\tobject.onBeforeRender( _this, scene, camera, geometry, material, group );\n\n\t\t\tif ( object.isImmediateRenderObject ) {\n\n\t\t\t\tsetMaterial( material );\n\n\t\t\t\tvar program = setProgram( camera, scene.fog, material, object );\n\n\t\t\t\t_currentGeometryProgram = '';\n\n\t\t\t\tobject.render( function ( object ) {\n\n\t\t\t\t\t_this.renderBufferImmediate( object, program, material );\n\n\t\t\t\t} );\n\n\t\t\t} else {\n\n\t\t\t\t_this.renderBufferDirect( camera, scene.fog, geometry, material, object, group );\n\n\t\t\t}\n\n\t\t\tobject.onAfterRender( _this, scene, camera, geometry, material, group );\n\n\n\t\t}\n\n\t}\n\n\tfunction initMaterial( material, fog, object ) {\n\n\t\tvar materialProperties = properties.get( material );\n\n\t\tvar parameters = programCache.getParameters(\n\t\t\tmaterial, _lights, fog, _clipping.numPlanes, _clipping.numIntersection, object );\n\n\t\tvar code = programCache.getProgramCode( material, parameters );\n\n\t\tvar program = materialProperties.program;\n\t\tvar programChange = true;\n\n\t\tif ( program === undefined ) {\n\n\t\t\t// new material\n\t\t\tmaterial.addEventListener( 'dispose', onMaterialDispose );\n\n\t\t} else if ( program.code !== code ) {\n\n\t\t\t// changed glsl or parameters\n\t\t\treleaseMaterialProgramReference( material );\n\n\t\t} else if ( parameters.shaderID !== undefined ) {\n\n\t\t\t// same glsl and uniform list\n\t\t\treturn;\n\n\t\t} else {\n\n\t\t\t// only rebuild uniform list\n\t\t\tprogramChange = false;\n\n\t\t}\n\n\t\tif ( programChange ) {\n\n\t\t\tif ( parameters.shaderID ) {\n\n\t\t\t\tvar shader = ShaderLib[ parameters.shaderID ];\n\n\t\t\t\tmaterialProperties.__webglShader = {\n\t\t\t\t\tname: material.type,\n\t\t\t\t\tuniforms: UniformsUtils.clone( shader.uniforms ),\n\t\t\t\t\tvertexShader: shader.vertexShader,\n\t\t\t\t\tfragmentShader: shader.fragmentShader\n\t\t\t\t};\n\n\t\t\t} else {\n\n\t\t\t\tmaterialProperties.__webglShader = {\n\t\t\t\t\tname: material.type,\n\t\t\t\t\tuniforms: material.uniforms,\n\t\t\t\t\tvertexShader: material.vertexShader,\n\t\t\t\t\tfragmentShader: material.fragmentShader\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t\tmaterial.__webglShader = materialProperties.__webglShader;\n\n\t\t\tprogram = programCache.acquireProgram( material, parameters, code );\n\n\t\t\tmaterialProperties.program = program;\n\t\t\tmaterial.program = program;\n\n\t\t}\n\n\t\tvar attributes = program.getAttributes();\n\n\t\tif ( material.morphTargets ) {\n\n\t\t\tmaterial.numSupportedMorphTargets = 0;\n\n\t\t\tfor ( var i = 0; i < _this.maxMorphTargets; i ++ ) {\n\n\t\t\t\tif ( attributes[ 'morphTarget' + i ] >= 0 ) {\n\n\t\t\t\t\tmaterial.numSupportedMorphTargets ++;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( material.morphNormals ) {\n\n\t\t\tmaterial.numSupportedMorphNormals = 0;\n\n\t\t\tfor ( var i = 0; i < _this.maxMorphNormals; i ++ ) {\n\n\t\t\t\tif ( attributes[ 'morphNormal' + i ] >= 0 ) {\n\n\t\t\t\t\tmaterial.numSupportedMorphNormals ++;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar uniforms = materialProperties.__webglShader.uniforms;\n\n\t\tif ( ! material.isShaderMaterial &&\n\t\t\t! material.isRawShaderMaterial ||\n\t\t\tmaterial.clipping === true ) {\n\n\t\t\tmaterialProperties.numClippingPlanes = _clipping.numPlanes;\n\t\t\tmaterialProperties.numIntersection = _clipping.numIntersection;\n\t\t\tuniforms.clippingPlanes = _clipping.uniform;\n\n\t\t}\n\n\t\tmaterialProperties.fog = fog;\n\n\t\t// store the light setup it was created for\n\n\t\tmaterialProperties.lightsHash = _lights.hash;\n\n\t\tif ( material.lights ) {\n\n\t\t\t// wire up the material to this renderer's lighting state\n\n\t\t\tuniforms.ambientLightColor.value = _lights.ambient;\n\t\t\tuniforms.directionalLights.value = _lights.directional;\n\t\t\tuniforms.spotLights.value = _lights.spot;\n\t\t\tuniforms.rectAreaLights.value = _lights.rectArea;\n\t\t\tuniforms.pointLights.value = _lights.point;\n\t\t\tuniforms.hemisphereLights.value = _lights.hemi;\n\n\t\t\tuniforms.directionalShadowMap.value = _lights.directionalShadowMap;\n\t\t\tuniforms.directionalShadowMatrix.value = _lights.directionalShadowMatrix;\n\t\t\tuniforms.spotShadowMap.value = _lights.spotShadowMap;\n\t\t\tuniforms.spotShadowMatrix.value = _lights.spotShadowMatrix;\n\t\t\tuniforms.pointShadowMap.value = _lights.pointShadowMap;\n\t\t\tuniforms.pointShadowMatrix.value = _lights.pointShadowMatrix;\n\t\t\t// TODO (abelnation): add area lights shadow info to uniforms\n\n\t\t}\n\n\t\tvar progUniforms = materialProperties.program.getUniforms(),\n\t\t\tuniformsList =\n\t\t\t\tWebGLUniforms.seqWithValue( progUniforms.seq, uniforms );\n\n\t\tmaterialProperties.uniformsList = uniformsList;\n\n\t}\n\n\tfunction setMaterial( material ) {\n\n\t\tmaterial.side === DoubleSide\n\t\t\t? state.disable( _gl.CULL_FACE )\n\t\t\t: state.enable( _gl.CULL_FACE );\n\n\t\tstate.setFlipSided( material.side === BackSide );\n\n\t\tmaterial.transparent === true\n\t\t\t? state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha )\n\t\t\t: state.setBlending( NoBlending );\n\n\t\tstate.setDepthFunc( material.depthFunc );\n\t\tstate.setDepthTest( material.depthTest );\n\t\tstate.setDepthWrite( material.depthWrite );\n\t\tstate.setColorWrite( material.colorWrite );\n\t\tstate.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );\n\n\t}\n\n\tfunction setProgram( camera, fog, material, object ) {\n\n\t\t_usedTextureUnits = 0;\n\n\t\tvar materialProperties = properties.get( material );\n\n\t\tif ( _clippingEnabled ) {\n\n\t\t\tif ( _localClippingEnabled || camera !== _currentCamera ) {\n\n\t\t\t\tvar useCache =\n\t\t\t\t\tcamera === _currentCamera &&\n\t\t\t\t\tmaterial.id === _currentMaterialId;\n\n\t\t\t\t// we might want to call this function with some ClippingGroup\n\t\t\t\t// object instead of the material, once it becomes feasible\n\t\t\t\t// (#8465, #8379)\n\t\t\t\t_clipping.setState(\n\t\t\t\t\tmaterial.clippingPlanes, material.clipIntersection, material.clipShadows,\n\t\t\t\t\tcamera, materialProperties, useCache );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( material.needsUpdate === false ) {\n\n\t\t\tif ( materialProperties.program === undefined ) {\n\n\t\t\t\tmaterial.needsUpdate = true;\n\n\t\t\t} else if ( material.fog && materialProperties.fog !== fog ) {\n\n\t\t\t\tmaterial.needsUpdate = true;\n\n\t\t\t} else if ( material.lights && materialProperties.lightsHash !== _lights.hash ) {\n\n\t\t\t\tmaterial.needsUpdate = true;\n\n\t\t\t} else if ( materialProperties.numClippingPlanes !== undefined &&\n\t\t\t\t( materialProperties.numClippingPlanes !== _clipping.numPlanes ||\n\t\t\t\tmaterialProperties.numIntersection !== _clipping.numIntersection ) ) {\n\n\t\t\t\tmaterial.needsUpdate = true;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( material.needsUpdate ) {\n\n\t\t\tinitMaterial( material, fog, object );\n\t\t\tmaterial.needsUpdate = false;\n\n\t\t}\n\n\t\tvar refreshProgram = false;\n\t\tvar refreshMaterial = false;\n\t\tvar refreshLights = false;\n\n\t\tvar program = materialProperties.program,\n\t\t\tp_uniforms = program.getUniforms(),\n\t\t\tm_uniforms = materialProperties.__webglShader.uniforms;\n\n\t\tif ( program.id !== _currentProgram ) {\n\n\t\t\t_gl.useProgram( program.program );\n\t\t\t_currentProgram = program.id;\n\n\t\t\trefreshProgram = true;\n\t\t\trefreshMaterial = true;\n\t\t\trefreshLights = true;\n\n\t\t}\n\n\t\tif ( material.id !== _currentMaterialId ) {\n\n\t\t\t_currentMaterialId = material.id;\n\n\t\t\trefreshMaterial = true;\n\n\t\t}\n\n\t\tif ( refreshProgram || camera !== _currentCamera ) {\n\n\t\t\tp_uniforms.set( _gl, camera, 'projectionMatrix' );\n\n\t\t\tif ( capabilities.logarithmicDepthBuffer ) {\n\n\t\t\t\tp_uniforms.setValue( _gl, 'logDepthBufFC',\n\t\t\t\t\t2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );\n\n\t\t\t}\n\n\n\t\t\tif ( camera !== _currentCamera ) {\n\n\t\t\t\t_currentCamera = camera;\n\n\t\t\t\t// lighting uniforms depend on the camera so enforce an update\n\t\t\t\t// now, in case this material supports lights - or later, when\n\t\t\t\t// the next material that does gets activated:\n\n\t\t\t\trefreshMaterial = true;\t\t// set to true on material change\n\t\t\t\trefreshLights = true;\t\t// remains set until update done\n\n\t\t\t}\n\n\t\t\t// load material specific uniforms\n\t\t\t// (shader material also gets them for the sake of genericity)\n\n\t\t\tif ( material.isShaderMaterial ||\n\t\t\t\tmaterial.isMeshPhongMaterial ||\n\t\t\t\tmaterial.isMeshStandardMaterial ||\n\t\t\t\tmaterial.envMap ) {\n\n\t\t\t\tvar uCamPos = p_uniforms.map.cameraPosition;\n\n\t\t\t\tif ( uCamPos !== undefined ) {\n\n\t\t\t\t\tuCamPos.setValue( _gl,\n\t\t\t\t\t\t_vector3.setFromMatrixPosition( camera.matrixWorld ) );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( material.isMeshPhongMaterial ||\n\t\t\t\tmaterial.isMeshLambertMaterial ||\n\t\t\t\tmaterial.isMeshBasicMaterial ||\n\t\t\t\tmaterial.isMeshStandardMaterial ||\n\t\t\t\tmaterial.isShaderMaterial ||\n\t\t\t\tmaterial.skinning ) {\n\n\t\t\t\tp_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );\n\n\t\t\t}\n\n\t\t\tp_uniforms.set( _gl, _this, 'toneMappingExposure' );\n\t\t\tp_uniforms.set( _gl, _this, 'toneMappingWhitePoint' );\n\n\t\t}\n\n\t\t// skinning uniforms must be set even if material didn't change\n\t\t// auto-setting of texture unit for bone texture must go before other textures\n\t\t// not sure why, but otherwise weird things happen\n\n\t\tif ( material.skinning ) {\n\n\t\t\tp_uniforms.setOptional( _gl, object, 'bindMatrix' );\n\t\t\tp_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );\n\n\t\t\tvar skeleton = object.skeleton;\n\n\t\t\tif ( skeleton ) {\n\n\t\t\t\tif ( capabilities.floatVertexTextures && skeleton.useVertexTexture ) {\n\n\t\t\t\t\tp_uniforms.set( _gl, skeleton, 'boneTexture' );\n\t\t\t\t\tp_uniforms.set( _gl, skeleton, 'boneTextureWidth' );\n\t\t\t\t\tp_uniforms.set( _gl, skeleton, 'boneTextureHeight' );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tp_uniforms.setOptional( _gl, skeleton, 'boneMatrices' );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( refreshMaterial ) {\n\n\t\t\tif ( material.lights ) {\n\n\t\t\t\t// the current material requires lighting info\n\n\t\t\t\t// note: all lighting uniforms are always set correctly\n\t\t\t\t// they simply reference the renderer's state for their\n\t\t\t\t// values\n\t\t\t\t//\n\t\t\t\t// use the current material's .needsUpdate flags to set\n\t\t\t\t// the GL state when required\n\n\t\t\t\tmarkUniformsLightsNeedsUpdate( m_uniforms, refreshLights );\n\n\t\t\t}\n\n\t\t\t// refresh uniforms common to several materials\n\n\t\t\tif ( fog && material.fog ) {\n\n\t\t\t\trefreshUniformsFog( m_uniforms, fog );\n\n\t\t\t}\n\n\t\t\tif ( material.isMeshBasicMaterial ||\n\t\t\t\tmaterial.isMeshLambertMaterial ||\n\t\t\t\tmaterial.isMeshPhongMaterial ||\n\t\t\t\tmaterial.isMeshStandardMaterial ||\n\t\t\t\tmaterial.isMeshNormalMaterial ||\n\t\t\t\tmaterial.isMeshDepthMaterial ) {\n\n\t\t\t\trefreshUniformsCommon( m_uniforms, material );\n\n\t\t\t}\n\n\t\t\t// refresh single material specific uniforms\n\n\t\t\tif ( material.isLineBasicMaterial ) {\n\n\t\t\t\trefreshUniformsLine( m_uniforms, material );\n\n\t\t\t} else if ( material.isLineDashedMaterial ) {\n\n\t\t\t\trefreshUniformsLine( m_uniforms, material );\n\t\t\t\trefreshUniformsDash( m_uniforms, material );\n\n\t\t\t} else if ( material.isPointsMaterial ) {\n\n\t\t\t\trefreshUniformsPoints( m_uniforms, material );\n\n\t\t\t} else if ( material.isMeshLambertMaterial ) {\n\n\t\t\t\trefreshUniformsLambert( m_uniforms, material );\n\n\t\t\t} else if ( material.isMeshToonMaterial ) {\n\n\t\t\t\trefreshUniformsToon( m_uniforms, material );\n\n\t\t\t} else if ( material.isMeshPhongMaterial ) {\n\n\t\t\t\trefreshUniformsPhong( m_uniforms, material );\n\n\t\t\t} else if ( material.isMeshPhysicalMaterial ) {\n\n\t\t\t\trefreshUniformsPhysical( m_uniforms, material );\n\n\t\t\t} else if ( material.isMeshStandardMaterial ) {\n\n\t\t\t\trefreshUniformsStandard( m_uniforms, material );\n\n\t\t\t} else if ( material.isMeshDepthMaterial ) {\n\n\t\t\t\tif ( material.displacementMap ) {\n\n\t\t\t\t\tm_uniforms.displacementMap.value = material.displacementMap;\n\t\t\t\t\tm_uniforms.displacementScale.value = material.displacementScale;\n\t\t\t\t\tm_uniforms.displacementBias.value = material.displacementBias;\n\n\t\t\t\t}\n\n\t\t\t} else if ( material.isMeshNormalMaterial ) {\n\n\t\t\t\trefreshUniformsNormal( m_uniforms, material );\n\n\t\t\t}\n\n\t\t\t// RectAreaLight Texture\n\t\t\t// TODO (mrdoob): Find a nicer implementation\n\n\t\t\tif ( m_uniforms.ltcMat !== undefined ) m_uniforms.ltcMat.value = THREE.UniformsLib.LTC_MAT_TEXTURE;\n\t\t\tif ( m_uniforms.ltcMag !== undefined ) m_uniforms.ltcMag.value = THREE.UniformsLib.LTC_MAG_TEXTURE;\n\n\t\t\tWebGLUniforms.upload(\n\t\t\t\t_gl, materialProperties.uniformsList, m_uniforms, _this );\n\n\t\t}\n\n\n\t\t// common matrices\n\n\t\tp_uniforms.set( _gl, object, 'modelViewMatrix' );\n\t\tp_uniforms.set( _gl, object, 'normalMatrix' );\n\t\tp_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );\n\n\t\treturn program;\n\n\t}\n\n\t// Uniforms (refresh uniforms objects)\n\n\tfunction refreshUniformsCommon( uniforms, material ) {\n\n\t\tuniforms.opacity.value = material.opacity;\n\n\t\tuniforms.diffuse.value = material.color;\n\n\t\tif ( material.emissive ) {\n\n\t\t\tuniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );\n\n\t\t}\n\n\t\tuniforms.map.value = material.map;\n\t\tuniforms.specularMap.value = material.specularMap;\n\t\tuniforms.alphaMap.value = material.alphaMap;\n\n\t\tif ( material.lightMap ) {\n\n\t\t\tuniforms.lightMap.value = material.lightMap;\n\t\t\tuniforms.lightMapIntensity.value = material.lightMapIntensity;\n\n\t\t}\n\n\t\tif ( material.aoMap ) {\n\n\t\t\tuniforms.aoMap.value = material.aoMap;\n\t\t\tuniforms.aoMapIntensity.value = material.aoMapIntensity;\n\n\t\t}\n\n\t\t// uv repeat and offset setting priorities\n\t\t// 1. color map\n\t\t// 2. specular map\n\t\t// 3. normal map\n\t\t// 4. bump map\n\t\t// 5. alpha map\n\t\t// 6. emissive map\n\n\t\tvar uvScaleMap;\n\n\t\tif ( material.map ) {\n\n\t\t\tuvScaleMap = material.map;\n\n\t\t} else if ( material.specularMap ) {\n\n\t\t\tuvScaleMap = material.specularMap;\n\n\t\t} else if ( material.displacementMap ) {\n\n\t\t\tuvScaleMap = material.displacementMap;\n\n\t\t} else if ( material.normalMap ) {\n\n\t\t\tuvScaleMap = material.normalMap;\n\n\t\t} else if ( material.bumpMap ) {\n\n\t\t\tuvScaleMap = material.bumpMap;\n\n\t\t} else if ( material.roughnessMap ) {\n\n\t\t\tuvScaleMap = material.roughnessMap;\n\n\t\t} else if ( material.metalnessMap ) {\n\n\t\t\tuvScaleMap = material.metalnessMap;\n\n\t\t} else if ( material.alphaMap ) {\n\n\t\t\tuvScaleMap = material.alphaMap;\n\n\t\t} else if ( material.emissiveMap ) {\n\n\t\t\tuvScaleMap = material.emissiveMap;\n\n\t\t}\n\n\t\tif ( uvScaleMap !== undefined ) {\n\n\t\t\t// backwards compatibility\n\t\t\tif ( uvScaleMap.isWebGLRenderTarget ) {\n\n\t\t\t\tuvScaleMap = uvScaleMap.texture;\n\n\t\t\t}\n\n\t\t\tvar offset = uvScaleMap.offset;\n\t\t\tvar repeat = uvScaleMap.repeat;\n\n\t\t\tuniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );\n\n\t\t}\n\n\t\tuniforms.envMap.value = material.envMap;\n\n\t\t// don't flip CubeTexture envMaps, flip everything else:\n\t\t// WebGLRenderTargetCube will be flipped for backwards compatibility\n\t\t// WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture\n\t\t// this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the future\n\t\tuniforms.flipEnvMap.value = ( ! ( material.envMap && material.envMap.isCubeTexture ) ) ? 1 : - 1;\n\n\t\tuniforms.reflectivity.value = material.reflectivity;\n\t\tuniforms.refractionRatio.value = material.refractionRatio;\n\n\t}\n\n\tfunction refreshUniformsLine( uniforms, material ) {\n\n\t\tuniforms.diffuse.value = material.color;\n\t\tuniforms.opacity.value = material.opacity;\n\n\t}\n\n\tfunction refreshUniformsDash( uniforms, material ) {\n\n\t\tuniforms.dashSize.value = material.dashSize;\n\t\tuniforms.totalSize.value = material.dashSize + material.gapSize;\n\t\tuniforms.scale.value = material.scale;\n\n\t}\n\n\tfunction refreshUniformsPoints( uniforms, material ) {\n\n\t\tuniforms.diffuse.value = material.color;\n\t\tuniforms.opacity.value = material.opacity;\n\t\tuniforms.size.value = material.size * _pixelRatio;\n\t\tuniforms.scale.value = _height * 0.5;\n\n\t\tuniforms.map.value = material.map;\n\n\t\tif ( material.map !== null ) {\n\n\t\t\tvar offset = material.map.offset;\n\t\t\tvar repeat = material.map.repeat;\n\n\t\t\tuniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsFog( uniforms, fog ) {\n\n\t\tuniforms.fogColor.value = fog.color;\n\n\t\tif ( fog.isFog ) {\n\n\t\t\tuniforms.fogNear.value = fog.near;\n\t\t\tuniforms.fogFar.value = fog.far;\n\n\t\t} else if ( fog.isFogExp2 ) {\n\n\t\t\tuniforms.fogDensity.value = fog.density;\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsLambert( uniforms, material ) {\n\n\t\tif ( material.emissiveMap ) {\n\n\t\t\tuniforms.emissiveMap.value = material.emissiveMap;\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsPhong( uniforms, material ) {\n\n\t\tuniforms.specular.value = material.specular;\n\t\tuniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )\n\n\t\tif ( material.emissiveMap ) {\n\n\t\t\tuniforms.emissiveMap.value = material.emissiveMap;\n\n\t\t}\n\n\t\tif ( material.bumpMap ) {\n\n\t\t\tuniforms.bumpMap.value = material.bumpMap;\n\t\t\tuniforms.bumpScale.value = material.bumpScale;\n\n\t\t}\n\n\t\tif ( material.normalMap ) {\n\n\t\t\tuniforms.normalMap.value = material.normalMap;\n\t\t\tuniforms.normalScale.value.copy( material.normalScale );\n\n\t\t}\n\n\t\tif ( material.displacementMap ) {\n\n\t\t\tuniforms.displacementMap.value = material.displacementMap;\n\t\t\tuniforms.displacementScale.value = material.displacementScale;\n\t\t\tuniforms.displacementBias.value = material.displacementBias;\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsToon( uniforms, material ) {\n\n\t\trefreshUniformsPhong( uniforms, material );\n\n\t\tif ( material.gradientMap ) {\n\n\t\t\tuniforms.gradientMap.value = material.gradientMap;\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsStandard( uniforms, material ) {\n\n\t\tuniforms.roughness.value = material.roughness;\n\t\tuniforms.metalness.value = material.metalness;\n\n\t\tif ( material.roughnessMap ) {\n\n\t\t\tuniforms.roughnessMap.value = material.roughnessMap;\n\n\t\t}\n\n\t\tif ( material.metalnessMap ) {\n\n\t\t\tuniforms.metalnessMap.value = material.metalnessMap;\n\n\t\t}\n\n\t\tif ( material.emissiveMap ) {\n\n\t\t\tuniforms.emissiveMap.value = material.emissiveMap;\n\n\t\t}\n\n\t\tif ( material.bumpMap ) {\n\n\t\t\tuniforms.bumpMap.value = material.bumpMap;\n\t\t\tuniforms.bumpScale.value = material.bumpScale;\n\n\t\t}\n\n\t\tif ( material.normalMap ) {\n\n\t\t\tuniforms.normalMap.value = material.normalMap;\n\t\t\tuniforms.normalScale.value.copy( material.normalScale );\n\n\t\t}\n\n\t\tif ( material.displacementMap ) {\n\n\t\t\tuniforms.displacementMap.value = material.displacementMap;\n\t\t\tuniforms.displacementScale.value = material.displacementScale;\n\t\t\tuniforms.displacementBias.value = material.displacementBias;\n\n\t\t}\n\n\t\tif ( material.envMap ) {\n\n\t\t\t//uniforms.envMap.value = material.envMap; // part of uniforms common\n\t\t\tuniforms.envMapIntensity.value = material.envMapIntensity;\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsPhysical( uniforms, material ) {\n\n\t\tuniforms.clearCoat.value = material.clearCoat;\n\t\tuniforms.clearCoatRoughness.value = material.clearCoatRoughness;\n\n\t\trefreshUniformsStandard( uniforms, material );\n\n\t}\n\n\tfunction refreshUniformsNormal( uniforms, material ) {\n\n\t\tif ( material.bumpMap ) {\n\n\t\t\tuniforms.bumpMap.value = material.bumpMap;\n\t\t\tuniforms.bumpScale.value = material.bumpScale;\n\n\t\t}\n\n\t\tif ( material.normalMap ) {\n\n\t\t\tuniforms.normalMap.value = material.normalMap;\n\t\t\tuniforms.normalScale.value.copy( material.normalScale );\n\n\t\t}\n\n\t\tif ( material.displacementMap ) {\n\n\t\t\tuniforms.displacementMap.value = material.displacementMap;\n\t\t\tuniforms.displacementScale.value = material.displacementScale;\n\t\t\tuniforms.displacementBias.value = material.displacementBias;\n\n\t\t}\n\n\t}\n\n\t// If uniforms are marked as clean, they don't need to be loaded to the GPU.\n\n\tfunction markUniformsLightsNeedsUpdate( uniforms, value ) {\n\n\t\tuniforms.ambientLightColor.needsUpdate = value;\n\n\t\tuniforms.directionalLights.needsUpdate = value;\n\t\tuniforms.pointLights.needsUpdate = value;\n\t\tuniforms.spotLights.needsUpdate = value;\n\t\tuniforms.rectAreaLights.needsUpdate = value;\n\t\tuniforms.hemisphereLights.needsUpdate = value;\n\n\t}\n\n\t// Lighting\n\n\tfunction setupShadows( lights ) {\n\n\t\tvar lightShadowsLength = 0;\n\n\t\tfor ( var i = 0, l = lights.length; i < l; i ++ ) {\n\n\t\t\tvar light = lights[ i ];\n\n\t\t\tif ( light.castShadow ) {\n\n\t\t\t\t_lights.shadows[ lightShadowsLength ++ ] = light;\n\n\t\t\t}\n\n\t\t}\n\n\t\t_lights.shadows.length = lightShadowsLength;\n\n\t}\n\n\tfunction setupLights( lights, camera ) {\n\n\t\tvar l, ll, light,\n\t\t\tr = 0, g = 0, b = 0,\n\t\t\tcolor,\n\t\t\tintensity,\n\t\t\tdistance,\n\t\t\tshadowMap,\n\n\t\t\tviewMatrix = camera.matrixWorldInverse,\n\n\t\tdirectionalLength = 0,\n\t\tpointLength = 0,\n\t\tspotLength = 0,\n\t\trectAreaLength = 0,\n\t\themiLength = 0;\n\n\t\tfor ( l = 0, ll = lights.length; l < ll; l ++ ) {\n\n\t\t\tlight = lights[ l ];\n\n\t\t\tcolor = light.color;\n\t\t\tintensity = light.intensity;\n\t\t\tdistance = light.distance;\n\n\t\t\tshadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;\n\n\t\t\tif ( light.isAmbientLight ) {\n\n\t\t\t\tr += color.r * intensity;\n\t\t\t\tg += color.g * intensity;\n\t\t\t\tb += color.b * intensity;\n\n\t\t\t} else if ( light.isDirectionalLight ) {\n\n\t\t\t\tvar uniforms = lightCache.get( light );\n\n\t\t\t\tuniforms.color.copy( light.color ).multiplyScalar( light.intensity );\n\t\t\t\tuniforms.direction.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\t_vector3.setFromMatrixPosition( light.target.matrixWorld );\n\t\t\t\tuniforms.direction.sub( _vector3 );\n\t\t\t\tuniforms.direction.transformDirection( viewMatrix );\n\n\t\t\t\tuniforms.shadow = light.castShadow;\n\n\t\t\t\tif ( light.castShadow ) {\n\n\t\t\t\t\tuniforms.shadowBias = light.shadow.bias;\n\t\t\t\t\tuniforms.shadowRadius = light.shadow.radius;\n\t\t\t\t\tuniforms.shadowMapSize = light.shadow.mapSize;\n\n\t\t\t\t}\n\n\t\t\t\t_lights.directionalShadowMap[ directionalLength ] = shadowMap;\n\t\t\t\t_lights.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;\n\t\t\t\t_lights.directional[ directionalLength ++ ] = uniforms;\n\n\t\t\t} else if ( light.isSpotLight ) {\n\n\t\t\t\tvar uniforms = lightCache.get( light );\n\n\t\t\t\tuniforms.position.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\tuniforms.position.applyMatrix4( viewMatrix );\n\n\t\t\t\tuniforms.color.copy( color ).multiplyScalar( intensity );\n\t\t\t\tuniforms.distance = distance;\n\n\t\t\t\tuniforms.direction.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\t_vector3.setFromMatrixPosition( light.target.matrixWorld );\n\t\t\t\tuniforms.direction.sub( _vector3 );\n\t\t\t\tuniforms.direction.transformDirection( viewMatrix );\n\n\t\t\t\tuniforms.coneCos = Math.cos( light.angle );\n\t\t\t\tuniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );\n\t\t\t\tuniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay;\n\n\t\t\t\tuniforms.shadow = light.castShadow;\n\n\t\t\t\tif ( light.castShadow ) {\n\n\t\t\t\t\tuniforms.shadowBias = light.shadow.bias;\n\t\t\t\t\tuniforms.shadowRadius = light.shadow.radius;\n\t\t\t\t\tuniforms.shadowMapSize = light.shadow.mapSize;\n\n\t\t\t\t}\n\n\t\t\t\t_lights.spotShadowMap[ spotLength ] = shadowMap;\n\t\t\t\t_lights.spotShadowMatrix[ spotLength ] = light.shadow.matrix;\n\t\t\t\t_lights.spot[ spotLength ++ ] = uniforms;\n\n\t\t\t} else if ( light.isRectAreaLight ) {\n\n\t\t\t\tvar uniforms = lightCache.get( light );\n\n\t\t\t\t// (a) intensity controls irradiance of entire light\n\t\t\t\tuniforms.color\n\t\t\t\t\t.copy( color )\n\t\t\t\t\t.multiplyScalar( intensity / ( light.width * light.height ) );\n\n\t\t\t\t// (b) intensity controls the radiance per light area\n\t\t\t\t// uniforms.color.copy( color ).multiplyScalar( intensity );\n\n\t\t\t\tuniforms.position.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\tuniforms.position.applyMatrix4( viewMatrix );\n\n\t\t\t\t// extract local rotation of light to derive width/height half vectors\n\t\t\t\t_matrix42.identity();\n\t\t\t\t_matrix4.copy( light.matrixWorld );\n\t\t\t\t_matrix4.premultiply( viewMatrix );\n\t\t\t\t_matrix42.extractRotation( _matrix4 );\n\n\t\t\t\tuniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );\n\t\t\t\tuniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );\n\n\t\t\t\tuniforms.halfWidth.applyMatrix4( _matrix42 );\n\t\t\t\tuniforms.halfHeight.applyMatrix4( _matrix42 );\n\n\t\t\t\t// TODO (abelnation): RectAreaLight distance?\n\t\t\t\t// uniforms.distance = distance;\n\n\t\t\t\t_lights.rectArea[ rectAreaLength ++ ] = uniforms;\n\n\t\t\t} else if ( light.isPointLight ) {\n\n\t\t\t\tvar uniforms = lightCache.get( light );\n\n\t\t\t\tuniforms.position.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\tuniforms.position.applyMatrix4( viewMatrix );\n\n\t\t\t\tuniforms.color.copy( light.color ).multiplyScalar( light.intensity );\n\t\t\t\tuniforms.distance = light.distance;\n\t\t\t\tuniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay;\n\n\t\t\t\tuniforms.shadow = light.castShadow;\n\n\t\t\t\tif ( light.castShadow ) {\n\n\t\t\t\t\tuniforms.shadowBias = light.shadow.bias;\n\t\t\t\t\tuniforms.shadowRadius = light.shadow.radius;\n\t\t\t\t\tuniforms.shadowMapSize = light.shadow.mapSize;\n\n\t\t\t\t}\n\n\t\t\t\t_lights.pointShadowMap[ pointLength ] = shadowMap;\n\n\t\t\t\tif ( _lights.pointShadowMatrix[ pointLength ] === undefined ) {\n\n\t\t\t\t\t_lights.pointShadowMatrix[ pointLength ] = new Matrix4();\n\n\t\t\t\t}\n\n\t\t\t\t// for point lights we set the shadow matrix to be a translation-only matrix\n\t\t\t\t// equal to inverse of the light's position\n\t\t\t\t_vector3.setFromMatrixPosition( light.matrixWorld ).negate();\n\t\t\t\t_lights.pointShadowMatrix[ pointLength ].identity().setPosition( _vector3 );\n\n\t\t\t\t_lights.point[ pointLength ++ ] = uniforms;\n\n\t\t\t} else if ( light.isHemisphereLight ) {\n\n\t\t\t\tvar uniforms = lightCache.get( light );\n\n\t\t\t\tuniforms.direction.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\tuniforms.direction.transformDirection( viewMatrix );\n\t\t\t\tuniforms.direction.normalize();\n\n\t\t\t\tuniforms.skyColor.copy( light.color ).multiplyScalar( intensity );\n\t\t\t\tuniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );\n\n\t\t\t\t_lights.hemi[ hemiLength ++ ] = uniforms;\n\n\t\t\t}\n\n\t\t}\n\n\t\t_lights.ambient[ 0 ] = r;\n\t\t_lights.ambient[ 1 ] = g;\n\t\t_lights.ambient[ 2 ] = b;\n\n\t\t_lights.directional.length = directionalLength;\n\t\t_lights.spot.length = spotLength;\n\t\t_lights.rectArea.length = rectAreaLength;\n\t\t_lights.point.length = pointLength;\n\t\t_lights.hemi.length = hemiLength;\n\n\t\t// TODO (sam-g-steel) why aren't we using join\n\t\t_lights.hash = directionalLength + ',' + pointLength + ',' + spotLength + ',' + rectAreaLength + ',' + hemiLength + ',' + _lights.shadows.length;\n\n\t}\n\n\t// GL state setting\n\n\tthis.setFaceCulling = function ( cullFace, frontFaceDirection ) {\n\n\t\tstate.setCullFace( cullFace );\n\t\tstate.setFlipSided( frontFaceDirection === FrontFaceDirectionCW );\n\n\t};\n\n\t// Textures\n\n\tfunction allocTextureUnit() {\n\n\t\tvar textureUnit = _usedTextureUnits;\n\n\t\tif ( textureUnit >= capabilities.maxTextures ) {\n\n\t\t\tconsole.warn( 'WebGLRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures );\n\n\t\t}\n\n\t\t_usedTextureUnits += 1;\n\n\t\treturn textureUnit;\n\n\t}\n\n\tthis.allocTextureUnit = allocTextureUnit;\n\n\t// this.setTexture2D = setTexture2D;\n\tthis.setTexture2D = ( function() {\n\n\t\tvar warned = false;\n\n\t\t// backwards compatibility: peel texture.texture\n\t\treturn function setTexture2D( texture, slot ) {\n\n\t\t\tif ( texture && texture.isWebGLRenderTarget ) {\n\n\t\t\t\tif ( ! warned ) {\n\n\t\t\t\t\tconsole.warn( \"THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead.\" );\n\t\t\t\t\twarned = true;\n\n\t\t\t\t}\n\n\t\t\t\ttexture = texture.texture;\n\n\t\t\t}\n\n\t\t\ttextures.setTexture2D( texture, slot );\n\n\t\t};\n\n\t}() );\n\n\tthis.setTexture = ( function() {\n\n\t\tvar warned = false;\n\n\t\treturn function setTexture( texture, slot ) {\n\n\t\t\tif ( ! warned ) {\n\n\t\t\t\tconsole.warn( \"THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead.\" );\n\t\t\t\twarned = true;\n\n\t\t\t}\n\n\t\t\ttextures.setTexture2D( texture, slot );\n\n\t\t};\n\n\t}() );\n\n\tthis.setTextureCube = ( function() {\n\n\t\tvar warned = false;\n\n\t\treturn function setTextureCube( texture, slot ) {\n\n\t\t\t// backwards compatibility: peel texture.texture\n\t\t\tif ( texture && texture.isWebGLRenderTargetCube ) {\n\n\t\t\t\tif ( ! warned ) {\n\n\t\t\t\t\tconsole.warn( \"THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead.\" );\n\t\t\t\t\twarned = true;\n\n\t\t\t\t}\n\n\t\t\t\ttexture = texture.texture;\n\n\t\t\t}\n\n\t\t\t// currently relying on the fact that WebGLRenderTargetCube.texture is a Texture and NOT a CubeTexture\n\t\t\t// TODO: unify these code paths\n\t\t\tif ( ( texture && texture.isCubeTexture ) ||\n\t\t\t\t( Array.isArray( texture.image ) && texture.image.length === 6 ) ) {\n\n\t\t\t\t// CompressedTexture can have Array in image :/\n\n\t\t\t\t// this function alone should take care of cube textures\n\t\t\t\ttextures.setTextureCube( texture, slot );\n\n\t\t\t} else {\n\n\t\t\t\t// assumed: texture property of THREE.WebGLRenderTargetCube\n\n\t\t\t\ttextures.setTextureCubeDynamic( texture, slot );\n\n\t\t\t}\n\n\t\t};\n\n\t}() );\n\n\tthis.getCurrentRenderTarget = function() {\n\n\t\treturn _currentRenderTarget;\n\n\t};\n\n\tthis.setRenderTarget = function ( renderTarget ) {\n\n\t\t_currentRenderTarget = renderTarget;\n\n\t\tif ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) {\n\n\t\t\ttextures.setupRenderTarget( renderTarget );\n\n\t\t}\n\n\t\tvar isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube );\n\t\tvar framebuffer;\n\n\t\tif ( renderTarget ) {\n\n\t\t\tvar renderTargetProperties = properties.get( renderTarget );\n\n\t\t\tif ( isCube ) {\n\n\t\t\t\tframebuffer = renderTargetProperties.__webglFramebuffer[ renderTarget.activeCubeFace ];\n\n\t\t\t} else {\n\n\t\t\t\tframebuffer = renderTargetProperties.__webglFramebuffer;\n\n\t\t\t}\n\n\t\t\t_currentScissor.copy( renderTarget.scissor );\n\t\t\t_currentScissorTest = renderTarget.scissorTest;\n\n\t\t\t_currentViewport.copy( renderTarget.viewport );\n\n\t\t} else {\n\n\t\t\tframebuffer = null;\n\n\t\t\t_currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio );\n\t\t\t_currentScissorTest = _scissorTest;\n\n\t\t\t_currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio );\n\n\t\t}\n\n\t\tif ( _currentFramebuffer !== framebuffer ) {\n\n\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\t\t\t_currentFramebuffer = framebuffer;\n\n\t\t}\n\n\t\tstate.scissor( _currentScissor );\n\t\tstate.setScissorTest( _currentScissorTest );\n\n\t\tstate.viewport( _currentViewport );\n\n\t\tif ( isCube ) {\n\n\t\t\tvar textureProperties = properties.get( renderTarget.texture );\n\t\t\t_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, textureProperties.__webglTexture, renderTarget.activeMipMapLevel );\n\n\t\t}\n\n\t};\n\n\tthis.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer ) {\n\n\t\tif ( ( renderTarget && renderTarget.isWebGLRenderTarget ) === false ) {\n\n\t\t\tconsole.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tvar framebuffer = properties.get( renderTarget ).__webglFramebuffer;\n\n\t\tif ( framebuffer ) {\n\n\t\t\tvar restore = false;\n\n\t\t\tif ( framebuffer !== _currentFramebuffer ) {\n\n\t\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\t\t\trestore = true;\n\n\t\t\t}\n\n\t\t\ttry {\n\n\t\t\t\tvar texture = renderTarget.texture;\n\t\t\t\tvar textureFormat = texture.format;\n\t\t\t\tvar textureType = texture.type;\n\n\t\t\t\tif ( textureFormat !== RGBAFormat && paramThreeToGL( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {\n\n\t\t\t\t\tconsole.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\tif ( textureType !== UnsignedByteType && paramThreeToGL( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // IE11, Edge and Chrome Mac < 52 (#9513)\n\t\t\t\t\t! ( textureType === FloatType && ( extensions.get( 'OES_texture_float' ) || extensions.get( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox\n\t\t\t\t\t! ( textureType === HalfFloatType && extensions.get( 'EXT_color_buffer_half_float' ) ) ) {\n\n\t\t\t\t\tconsole.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\tif ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) {\n\n\t\t\t\t\t// the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)\n\n\t\t\t\t\tif ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {\n\n\t\t\t\t\t\t_gl.readPixels( x, y, width, height, paramThreeToGL( textureFormat ), paramThreeToGL( textureType ), buffer );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );\n\n\t\t\t\t}\n\n\t\t\t} finally {\n\n\t\t\t\tif ( restore ) {\n\n\t\t\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t};\n\n\t// Map three.js constants to WebGL constants\n\n\tfunction paramThreeToGL( p ) {\n\n\t\tvar extension;\n\n\t\tif ( p === RepeatWrapping ) return _gl.REPEAT;\n\t\tif ( p === ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE;\n\t\tif ( p === MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT;\n\n\t\tif ( p === NearestFilter ) return _gl.NEAREST;\n\t\tif ( p === NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST;\n\t\tif ( p === NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR;\n\n\t\tif ( p === LinearFilter ) return _gl.LINEAR;\n\t\tif ( p === LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST;\n\t\tif ( p === LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR;\n\n\t\tif ( p === UnsignedByteType ) return _gl.UNSIGNED_BYTE;\n\t\tif ( p === UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4;\n\t\tif ( p === UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1;\n\t\tif ( p === UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5;\n\n\t\tif ( p === ByteType ) return _gl.BYTE;\n\t\tif ( p === ShortType ) return _gl.SHORT;\n\t\tif ( p === UnsignedShortType ) return _gl.UNSIGNED_SHORT;\n\t\tif ( p === IntType ) return _gl.INT;\n\t\tif ( p === UnsignedIntType ) return _gl.UNSIGNED_INT;\n\t\tif ( p === FloatType ) return _gl.FLOAT;\n\n\t\tif ( p === HalfFloatType ) {\n\n\t\t\textension = extensions.get( 'OES_texture_half_float' );\n\n\t\t\tif ( extension !== null ) return extension.HALF_FLOAT_OES;\n\n\t\t}\n\n\t\tif ( p === AlphaFormat ) return _gl.ALPHA;\n\t\tif ( p === RGBFormat ) return _gl.RGB;\n\t\tif ( p === RGBAFormat ) return _gl.RGBA;\n\t\tif ( p === LuminanceFormat ) return _gl.LUMINANCE;\n\t\tif ( p === LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA;\n\t\tif ( p === DepthFormat ) return _gl.DEPTH_COMPONENT;\n\t\tif ( p === DepthStencilFormat ) return _gl.DEPTH_STENCIL;\n\n\t\tif ( p === AddEquation ) return _gl.FUNC_ADD;\n\t\tif ( p === SubtractEquation ) return _gl.FUNC_SUBTRACT;\n\t\tif ( p === ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT;\n\n\t\tif ( p === ZeroFactor ) return _gl.ZERO;\n\t\tif ( p === OneFactor ) return _gl.ONE;\n\t\tif ( p === SrcColorFactor ) return _gl.SRC_COLOR;\n\t\tif ( p === OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR;\n\t\tif ( p === SrcAlphaFactor ) return _gl.SRC_ALPHA;\n\t\tif ( p === OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA;\n\t\tif ( p === DstAlphaFactor ) return _gl.DST_ALPHA;\n\t\tif ( p === OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA;\n\n\t\tif ( p === DstColorFactor ) return _gl.DST_COLOR;\n\t\tif ( p === OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR;\n\t\tif ( p === SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE;\n\n\t\tif ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format ||\n\t\t\tp === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {\n\n\t\t\textension = extensions.get( 'WEBGL_compressed_texture_s3tc' );\n\n\t\t\tif ( extension !== null ) {\n\n\t\t\t\tif ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;\n\t\t\t\tif ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;\n\t\t\t\tif ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;\n\t\t\t\tif ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format ||\n\t\t\tp === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {\n\n\t\t\textension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );\n\n\t\t\tif ( extension !== null ) {\n\n\t\t\t\tif ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;\n\t\t\t\tif ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;\n\t\t\t\tif ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;\n\t\t\t\tif ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( p === RGB_ETC1_Format ) {\n\n\t\t\textension = extensions.get( 'WEBGL_compressed_texture_etc1' );\n\n\t\t\tif ( extension !== null ) return extension.COMPRESSED_RGB_ETC1_WEBGL;\n\n\t\t}\n\n\t\tif ( p === MinEquation || p === MaxEquation ) {\n\n\t\t\textension = extensions.get( 'EXT_blend_minmax' );\n\n\t\t\tif ( extension !== null ) {\n\n\t\t\t\tif ( p === MinEquation ) return extension.MIN_EXT;\n\t\t\t\tif ( p === MaxEquation ) return extension.MAX_EXT;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( p === UnsignedInt248Type ) {\n\n\t\t\textension = extensions.get( 'WEBGL_depth_texture' );\n\n\t\t\tif ( extension !== null ) return extension.UNSIGNED_INT_24_8_WEBGL;\n\n\t\t}\n\n\t\treturn 0;\n\n\t}\n\n}\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction FogExp2 ( color, density ) {\n\n\tthis.name = '';\n\n\tthis.color = new Color( color );\n\tthis.density = ( density !== undefined ) ? density : 0.00025;\n\n}\n\nFogExp2.prototype.isFogExp2 = true;\n\nFogExp2.prototype.clone = function () {\n\n\treturn new FogExp2( this.color.getHex(), this.density );\n\n};\n\nFogExp2.prototype.toJSON = function ( meta ) {\n\n\treturn {\n\t\ttype: 'FogExp2',\n\t\tcolor: this.color.getHex(),\n\t\tdensity: this.density\n\t};\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction Fog ( color, near, far ) {\n\n\tthis.name = '';\n\n\tthis.color = new Color( color );\n\n\tthis.near = ( near !== undefined ) ? near : 1;\n\tthis.far = ( far !== undefined ) ? far : 1000;\n\n}\n\nFog.prototype.isFog = true;\n\nFog.prototype.clone = function () {\n\n\treturn new Fog( this.color.getHex(), this.near, this.far );\n\n};\n\nFog.prototype.toJSON = function ( meta ) {\n\n\treturn {\n\t\ttype: 'Fog',\n\t\tcolor: this.color.getHex(),\n\t\tnear: this.near,\n\t\tfar: this.far\n\t};\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction Scene () {\n\n\tObject3D.call( this );\n\n\tthis.type = 'Scene';\n\n\tthis.background = null;\n\tthis.fog = null;\n\tthis.overrideMaterial = null;\n\n\tthis.autoUpdate = true; // checked by the renderer\n\n}\n\nScene.prototype = Object.create( Object3D.prototype );\n\nScene.prototype.constructor = Scene;\n\nScene.prototype.copy = function ( source, recursive ) {\n\n\tObject3D.prototype.copy.call( this, source, recursive );\n\n\tif ( source.background !== null ) this.background = source.background.clone();\n\tif ( source.fog !== null ) this.fog = source.fog.clone();\n\tif ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();\n\n\tthis.autoUpdate = source.autoUpdate;\n\tthis.matrixAutoUpdate = source.matrixAutoUpdate;\n\n\treturn this;\n\n};\n\nScene.prototype.toJSON = function ( meta ) {\n\n\tvar data = Object3D.prototype.toJSON.call( this, meta );\n\n\tif ( this.background !== null ) data.object.background = this.background.toJSON( meta );\n\tif ( this.fog !== null ) data.object.fog = this.fog.toJSON();\n\n\treturn data;\n\n};\n\n/**\n * @author mikael emtinger / http://gomo.se/\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction LensFlare( texture, size, distance, blending, color ) {\n\n\tObject3D.call( this );\n\n\tthis.lensFlares = [];\n\n\tthis.positionScreen = new Vector3();\n\tthis.customUpdateCallback = undefined;\n\n\tif ( texture !== undefined ) {\n\n\t\tthis.add( texture, size, distance, blending, color );\n\n\t}\n\n}\n\nLensFlare.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\tconstructor: LensFlare,\n\n\tisLensFlare: true,\n\n\tcopy: function ( source ) {\n\n\t\tObject3D.prototype.copy.call( this, source );\n\n\t\tthis.positionScreen.copy( source.positionScreen );\n\t\tthis.customUpdateCallback = source.customUpdateCallback;\n\n\t\tfor ( var i = 0, l = source.lensFlares.length; i < l; i ++ ) {\n\n\t\t\tthis.lensFlares.push( source.lensFlares[ i ] );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tadd: function ( texture, size, distance, blending, color, opacity ) {\n\n\t\tif ( size === undefined ) size = - 1;\n\t\tif ( distance === undefined ) distance = 0;\n\t\tif ( opacity === undefined ) opacity = 1;\n\t\tif ( color === undefined ) color = new Color( 0xffffff );\n\t\tif ( blending === undefined ) blending = NormalBlending;\n\n\t\tdistance = Math.min( distance, Math.max( 0, distance ) );\n\n\t\tthis.lensFlares.push( {\n\t\t\ttexture: texture,\t// THREE.Texture\n\t\t\tsize: size, \t\t// size in pixels (-1 = use texture.width)\n\t\t\tdistance: distance, \t// distance (0-1) from light source (0=at light source)\n\t\t\tx: 0, y: 0, z: 0,\t// screen position (-1 => 1) z = 0 is in front z = 1 is back\n\t\t\tscale: 1, \t\t// scale\n\t\t\trotation: 0, \t\t// rotation\n\t\t\topacity: opacity,\t// opacity\n\t\t\tcolor: color,\t\t// color\n\t\t\tblending: blending\t// blending\n\t\t} );\n\n\t},\n\n\t/*\n\t * Update lens flares update positions on all flares based on the screen position\n\t * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way.\n\t */\n\n\tupdateLensFlares: function () {\n\n\t\tvar f, fl = this.lensFlares.length;\n\t\tvar flare;\n\t\tvar vecX = - this.positionScreen.x * 2;\n\t\tvar vecY = - this.positionScreen.y * 2;\n\n\t\tfor ( f = 0; f < fl; f ++ ) {\n\n\t\t\tflare = this.lensFlares[ f ];\n\n\t\t\tflare.x = this.positionScreen.x + vecX * flare.distance;\n\t\t\tflare.y = this.positionScreen.y + vecY * flare.distance;\n\n\t\t\tflare.wantedRotation = flare.x * Math.PI * 0.25;\n\t\t\tflare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25;\n\n\t\t}\n\n\t}\n\n} );\n\n/**\n * @author alteredq / http://alteredqualia.com/\n *\n * parameters = {\n * color: ,\n * opacity: ,\n * map: new THREE.Texture( ),\n *\n *\tuvOffset: new THREE.Vector2(),\n *\tuvScale: new THREE.Vector2()\n * }\n */\n\nfunction SpriteMaterial( parameters ) {\n\n\tMaterial.call( this );\n\n\tthis.type = 'SpriteMaterial';\n\n\tthis.color = new Color( 0xffffff );\n\tthis.map = null;\n\n\tthis.rotation = 0;\n\n\tthis.fog = false;\n\tthis.lights = false;\n\n\tthis.setValues( parameters );\n\n}\n\nSpriteMaterial.prototype = Object.create( Material.prototype );\nSpriteMaterial.prototype.constructor = SpriteMaterial;\n\nSpriteMaterial.prototype.copy = function ( source ) {\n\n\tMaterial.prototype.copy.call( this, source );\n\n\tthis.color.copy( source.color );\n\tthis.map = source.map;\n\n\tthis.rotation = source.rotation;\n\n\treturn this;\n\n};\n\n/**\n * @author mikael emtinger / http://gomo.se/\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction Sprite( material ) {\n\n\tObject3D.call( this );\n\n\tthis.type = 'Sprite';\n\n\tthis.material = ( material !== undefined ) ? material : new SpriteMaterial();\n\n}\n\nSprite.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\tconstructor: Sprite,\n\n\tisSprite: true,\n\n\traycast: ( function () {\n\n\t\tvar matrixPosition = new Vector3();\n\n\t\treturn function raycast( raycaster, intersects ) {\n\n\t\t\tmatrixPosition.setFromMatrixPosition( this.matrixWorld );\n\n\t\t\tvar distanceSq = raycaster.ray.distanceSqToPoint( matrixPosition );\n\t\t\tvar guessSizeSq = this.scale.x * this.scale.y / 4;\n\n\t\t\tif ( distanceSq > guessSizeSq ) {\n\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tintersects.push( {\n\n\t\t\t\tdistance: Math.sqrt( distanceSq ),\n\t\t\t\tpoint: this.position,\n\t\t\t\tface: null,\n\t\t\t\tobject: this\n\n\t\t\t} );\n\n\t\t};\n\n\t}() ),\n\n\tclone: function () {\n\n\t\treturn new this.constructor( this.material ).copy( this );\n\n\t}\n\n} );\n\n/**\n * @author mikael emtinger / http://gomo.se/\n * @author alteredq / http://alteredqualia.com/\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction LOD() {\n\n\tObject3D.call( this );\n\n\tthis.type = 'LOD';\n\n\tObject.defineProperties( this, {\n\t\tlevels: {\n\t\t\tenumerable: true,\n\t\t\tvalue: []\n\t\t}\n\t} );\n\n}\n\n\nLOD.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\tconstructor: LOD,\n\n\tcopy: function ( source ) {\n\n\t\tObject3D.prototype.copy.call( this, source, false );\n\n\t\tvar levels = source.levels;\n\n\t\tfor ( var i = 0, l = levels.length; i < l; i ++ ) {\n\n\t\t\tvar level = levels[ i ];\n\n\t\t\tthis.addLevel( level.object.clone(), level.distance );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\taddLevel: function ( object, distance ) {\n\n\t\tif ( distance === undefined ) distance = 0;\n\n\t\tdistance = Math.abs( distance );\n\n\t\tvar levels = this.levels;\n\n\t\tfor ( var l = 0; l < levels.length; l ++ ) {\n\n\t\t\tif ( distance < levels[ l ].distance ) {\n\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tlevels.splice( l, 0, { distance: distance, object: object } );\n\n\t\tthis.add( object );\n\n\t},\n\n\tgetObjectForDistance: function ( distance ) {\n\n\t\tvar levels = this.levels;\n\n\t\tfor ( var i = 1, l = levels.length; i < l; i ++ ) {\n\n\t\t\tif ( distance < levels[ i ].distance ) {\n\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn levels[ i - 1 ].object;\n\n\t},\n\n\traycast: ( function () {\n\n\t\tvar matrixPosition = new Vector3();\n\n\t\treturn function raycast( raycaster, intersects ) {\n\n\t\t\tmatrixPosition.setFromMatrixPosition( this.matrixWorld );\n\n\t\t\tvar distance = raycaster.ray.origin.distanceTo( matrixPosition );\n\n\t\t\tthis.getObjectForDistance( distance ).raycast( raycaster, intersects );\n\n\t\t};\n\n\t}() ),\n\n\tupdate: function () {\n\n\t\tvar v1 = new Vector3();\n\t\tvar v2 = new Vector3();\n\n\t\treturn function update( camera ) {\n\n\t\t\tvar levels = this.levels;\n\n\t\t\tif ( levels.length > 1 ) {\n\n\t\t\t\tv1.setFromMatrixPosition( camera.matrixWorld );\n\t\t\t\tv2.setFromMatrixPosition( this.matrixWorld );\n\n\t\t\t\tvar distance = v1.distanceTo( v2 );\n\n\t\t\t\tlevels[ 0 ].object.visible = true;\n\n\t\t\t\tfor ( var i = 1, l = levels.length; i < l; i ++ ) {\n\n\t\t\t\t\tif ( distance >= levels[ i ].distance ) {\n\n\t\t\t\t\t\tlevels[ i - 1 ].object.visible = false;\n\t\t\t\t\t\tlevels[ i ].object.visible = true;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tfor ( ; i < l; i ++ ) {\n\n\t\t\t\t\tlevels[ i ].object.visible = false;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t}(),\n\n\ttoJSON: function ( meta ) {\n\n\t\tvar data = Object3D.prototype.toJSON.call( this, meta );\n\n\t\tdata.object.levels = [];\n\n\t\tvar levels = this.levels;\n\n\t\tfor ( var i = 0, l = levels.length; i < l; i ++ ) {\n\n\t\t\tvar level = levels[ i ];\n\n\t\t\tdata.object.levels.push( {\n\t\t\t\tobject: level.object.uuid,\n\t\t\t\tdistance: level.distance\n\t\t\t} );\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n} );\n\n/**\n * @author mikael emtinger / http://gomo.se/\n * @author alteredq / http://alteredqualia.com/\n * @author michael guerrero / http://realitymeltdown.com\n * @author ikerr / http://verold.com\n */\n\nfunction Skeleton( bones, boneInverses, useVertexTexture ) {\n\n\tthis.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true;\n\n\tthis.identityMatrix = new Matrix4();\n\n\t// copy the bone array\n\n\tbones = bones || [];\n\n\tthis.bones = bones.slice( 0 );\n\n\t// create a bone texture or an array of floats\n\n\tif ( this.useVertexTexture ) {\n\n\t\t// layout (1 matrix = 4 pixels)\n\t\t// RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)\n\t\t// with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8)\n\t\t// 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16)\n\t\t// 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32)\n\t\t// 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)\n\n\n\t\tvar size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix\n\t\tsize = _Math.nextPowerOfTwo( Math.ceil( size ) );\n\t\tsize = Math.max( size, 4 );\n\n\t\tthis.boneTextureWidth = size;\n\t\tthis.boneTextureHeight = size;\n\n\t\tthis.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel\n\t\tthis.boneTexture = new DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, RGBAFormat, FloatType );\n\n\t} else {\n\n\t\tthis.boneMatrices = new Float32Array( 16 * this.bones.length );\n\n\t}\n\n\t// use the supplied bone inverses or calculate the inverses\n\n\tif ( boneInverses === undefined ) {\n\n\t\tthis.calculateInverses();\n\n\t} else {\n\n\t\tif ( this.bones.length === boneInverses.length ) {\n\n\t\t\tthis.boneInverses = boneInverses.slice( 0 );\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.Skeleton bonInverses is the wrong length.' );\n\n\t\t\tthis.boneInverses = [];\n\n\t\t\tfor ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {\n\n\t\t\t\tthis.boneInverses.push( new Matrix4() );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n\nObject.assign( Skeleton.prototype, {\n\n\tcalculateInverses: function () {\n\n\t\tthis.boneInverses = [];\n\n\t\tfor ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {\n\n\t\t\tvar inverse = new Matrix4();\n\n\t\t\tif ( this.bones[ b ] ) {\n\n\t\t\t\tinverse.getInverse( this.bones[ b ].matrixWorld );\n\n\t\t\t}\n\n\t\t\tthis.boneInverses.push( inverse );\n\n\t\t}\n\n\t},\n\n\tpose: function () {\n\n\t\tvar bone;\n\n\t\t// recover the bind-time world matrices\n\n\t\tfor ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {\n\n\t\t\tbone = this.bones[ b ];\n\n\t\t\tif ( bone ) {\n\n\t\t\t\tbone.matrixWorld.getInverse( this.boneInverses[ b ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// compute the local matrices, positions, rotations and scales\n\n\t\tfor ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {\n\n\t\t\tbone = this.bones[ b ];\n\n\t\t\tif ( bone ) {\n\n\t\t\t\tif ( bone.parent && bone.parent.isBone ) {\n\n\t\t\t\t\tbone.matrix.getInverse( bone.parent.matrixWorld );\n\t\t\t\t\tbone.matrix.multiply( bone.matrixWorld );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tbone.matrix.copy( bone.matrixWorld );\n\n\t\t\t\t}\n\n\t\t\t\tbone.matrix.decompose( bone.position, bone.quaternion, bone.scale );\n\n\t\t\t}\n\n\t\t}\n\n\t},\n\n\tupdate: ( function () {\n\n\t\tvar offsetMatrix = new Matrix4();\n\n\t\treturn function update() {\n\n\t\t\t// flatten bone matrices to array\n\n\t\t\tfor ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {\n\n\t\t\t\t// compute the offset between the current and the original transform\n\n\t\t\t\tvar matrix = this.bones[ b ] ? this.bones[ b ].matrixWorld : this.identityMatrix;\n\n\t\t\t\toffsetMatrix.multiplyMatrices( matrix, this.boneInverses[ b ] );\n\t\t\t\toffsetMatrix.toArray( this.boneMatrices, b * 16 );\n\n\t\t\t}\n\n\t\t\tif ( this.useVertexTexture ) {\n\n\t\t\t\tthis.boneTexture.needsUpdate = true;\n\n\t\t\t}\n\n\t\t};\n\n\t} )(),\n\n\tclone: function () {\n\n\t\treturn new Skeleton( this.bones, this.boneInverses, this.useVertexTexture );\n\n\t}\n\n} );\n\n/**\n * @author mikael emtinger / http://gomo.se/\n * @author alteredq / http://alteredqualia.com/\n * @author ikerr / http://verold.com\n */\n\nfunction Bone() {\n\n\tObject3D.call( this );\n\n\tthis.type = 'Bone';\n\n}\n\nBone.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\tconstructor: Bone,\n\n\tisBone: true\n\n} );\n\n/**\n * @author mikael emtinger / http://gomo.se/\n * @author alteredq / http://alteredqualia.com/\n * @author ikerr / http://verold.com\n */\n\nfunction SkinnedMesh( geometry, material, useVertexTexture ) {\n\n\tMesh.call( this, geometry, material );\n\n\tthis.type = 'SkinnedMesh';\n\n\tthis.bindMode = \"attached\";\n\tthis.bindMatrix = new Matrix4();\n\tthis.bindMatrixInverse = new Matrix4();\n\n\t// init bones\n\n\t// TODO: remove bone creation as there is no reason (other than\n\t// convenience) for THREE.SkinnedMesh to do this.\n\n\tvar bones = [];\n\n\tif ( this.geometry && this.geometry.bones !== undefined ) {\n\n\t\tvar bone, gbone;\n\n\t\tfor ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) {\n\n\t\t\tgbone = this.geometry.bones[ b ];\n\n\t\t\tbone = new Bone();\n\t\t\tbones.push( bone );\n\n\t\t\tbone.name = gbone.name;\n\t\t\tbone.position.fromArray( gbone.pos );\n\t\t\tbone.quaternion.fromArray( gbone.rotq );\n\t\t\tif ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl );\n\n\t\t}\n\n\t\tfor ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) {\n\n\t\t\tgbone = this.geometry.bones[ b ];\n\n\t\t\tif ( gbone.parent !== - 1 && gbone.parent !== null &&\n\t\t\t\t\tbones[ gbone.parent ] !== undefined ) {\n\n\t\t\t\tbones[ gbone.parent ].add( bones[ b ] );\n\n\t\t\t} else {\n\n\t\t\t\tthis.add( bones[ b ] );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tthis.normalizeSkinWeights();\n\n\tthis.updateMatrixWorld( true );\n\tthis.bind( new Skeleton( bones, undefined, useVertexTexture ), this.matrixWorld );\n\n}\n\n\nSkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {\n\n\tconstructor: SkinnedMesh,\n\n\tisSkinnedMesh: true,\n\n\tbind: function( skeleton, bindMatrix ) {\n\n\t\tthis.skeleton = skeleton;\n\n\t\tif ( bindMatrix === undefined ) {\n\n\t\t\tthis.updateMatrixWorld( true );\n\n\t\t\tthis.skeleton.calculateInverses();\n\n\t\t\tbindMatrix = this.matrixWorld;\n\n\t\t}\n\n\t\tthis.bindMatrix.copy( bindMatrix );\n\t\tthis.bindMatrixInverse.getInverse( bindMatrix );\n\n\t},\n\n\tpose: function () {\n\n\t\tthis.skeleton.pose();\n\n\t},\n\n\tnormalizeSkinWeights: function () {\n\n\t\tif ( this.geometry && this.geometry.isGeometry ) {\n\n\t\t\tfor ( var i = 0; i < this.geometry.skinWeights.length; i ++ ) {\n\n\t\t\t\tvar sw = this.geometry.skinWeights[ i ];\n\n\t\t\t\tvar scale = 1.0 / sw.lengthManhattan();\n\n\t\t\t\tif ( scale !== Infinity ) {\n\n\t\t\t\t\tsw.multiplyScalar( scale );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tsw.set( 1, 0, 0, 0 ); // do something reasonable\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else if ( this.geometry && this.geometry.isBufferGeometry ) {\n\n\t\t\tvar vec = new Vector4();\n\n\t\t\tvar skinWeight = this.geometry.attributes.skinWeight;\n\n\t\t\tfor ( var i = 0; i < skinWeight.count; i ++ ) {\n\n\t\t\t\tvec.x = skinWeight.getX( i );\n\t\t\t\tvec.y = skinWeight.getY( i );\n\t\t\t\tvec.z = skinWeight.getZ( i );\n\t\t\t\tvec.w = skinWeight.getW( i );\n\n\t\t\t\tvar scale = 1.0 / vec.lengthManhattan();\n\n\t\t\t\tif ( scale !== Infinity ) {\n\n\t\t\t\t\tvec.multiplyScalar( scale );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tvec.set( 1, 0, 0, 0 ); // do something reasonable\n\n\t\t\t\t}\n\n\t\t\t\tskinWeight.setXYZW( i, vec.x, vec.y, vec.z, vec.w );\n\n\t\t\t}\n\n\t\t}\n\n\t},\n\n\tupdateMatrixWorld: function( force ) {\n\n\t\tMesh.prototype.updateMatrixWorld.call( this, true );\n\n\t\tif ( this.bindMode === \"attached\" ) {\n\n\t\t\tthis.bindMatrixInverse.getInverse( this.matrixWorld );\n\n\t\t} else if ( this.bindMode === \"detached\" ) {\n\n\t\t\tthis.bindMatrixInverse.getInverse( this.bindMatrix );\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.SkinnedMesh unrecognized bindMode: ' + this.bindMode );\n\n\t\t}\n\n\t},\n\n\tclone: function() {\n\n\t\treturn new this.constructor( this.geometry, this.material, this.skeleton.useVertexTexture ).copy( this );\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author alteredq / http://alteredqualia.com/\n *\n * parameters = {\n * color: ,\n * opacity: ,\n *\n * linewidth: ,\n * linecap: \"round\",\n * linejoin: \"round\"\n * }\n */\n\nfunction LineBasicMaterial( parameters ) {\n\n\tMaterial.call( this );\n\n\tthis.type = 'LineBasicMaterial';\n\n\tthis.color = new Color( 0xffffff );\n\n\tthis.linewidth = 1;\n\tthis.linecap = 'round';\n\tthis.linejoin = 'round';\n\n\tthis.lights = false;\n\n\tthis.setValues( parameters );\n\n}\n\nLineBasicMaterial.prototype = Object.create( Material.prototype );\nLineBasicMaterial.prototype.constructor = LineBasicMaterial;\n\nLineBasicMaterial.prototype.isLineBasicMaterial = true;\n\nLineBasicMaterial.prototype.copy = function ( source ) {\n\n\tMaterial.prototype.copy.call( this, source );\n\n\tthis.color.copy( source.color );\n\n\tthis.linewidth = source.linewidth;\n\tthis.linecap = source.linecap;\n\tthis.linejoin = source.linejoin;\n\n\treturn this;\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction Line( geometry, material, mode ) {\n\n\tif ( mode === 1 ) {\n\n\t\tconsole.warn( 'THREE.Line: parameter THREE.LinePieces no longer supported. Created THREE.LineSegments instead.' );\n\t\treturn new LineSegments( geometry, material );\n\n\t}\n\n\tObject3D.call( this );\n\n\tthis.type = 'Line';\n\n\tthis.geometry = geometry !== undefined ? geometry : new BufferGeometry();\n\tthis.material = material !== undefined ? material : new LineBasicMaterial( { color: Math.random() * 0xffffff } );\n\n}\n\nLine.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\tconstructor: Line,\n\n\tisLine: true,\n\n\traycast: ( function () {\n\n\t\tvar inverseMatrix = new Matrix4();\n\t\tvar ray = new Ray();\n\t\tvar sphere = new Sphere();\n\n\t\treturn function raycast( raycaster, intersects ) {\n\n\t\t\tvar precision = raycaster.linePrecision;\n\t\t\tvar precisionSq = precision * precision;\n\n\t\t\tvar geometry = this.geometry;\n\t\t\tvar matrixWorld = this.matrixWorld;\n\n\t\t\t// Checking boundingSphere distance to ray\n\n\t\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\n\n\t\t\tsphere.copy( geometry.boundingSphere );\n\t\t\tsphere.applyMatrix4( matrixWorld );\n\n\t\t\tif ( raycaster.ray.intersectsSphere( sphere ) === false ) return;\n\n\t\t\t//\n\n\t\t\tinverseMatrix.getInverse( matrixWorld );\n\t\t\tray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );\n\n\t\t\tvar vStart = new Vector3();\n\t\t\tvar vEnd = new Vector3();\n\t\t\tvar interSegment = new Vector3();\n\t\t\tvar interRay = new Vector3();\n\t\t\tvar step = (this && this.isLineSegments) ? 2 : 1;\n\n\t\t\tif ( geometry.isBufferGeometry ) {\n\n\t\t\t\tvar index = geometry.index;\n\t\t\t\tvar attributes = geometry.attributes;\n\t\t\t\tvar positions = attributes.position.array;\n\n\t\t\t\tif ( index !== null ) {\n\n\t\t\t\t\tvar indices = index.array;\n\n\t\t\t\t\tfor ( var i = 0, l = indices.length - 1; i < l; i += step ) {\n\n\t\t\t\t\t\tvar a = indices[ i ];\n\t\t\t\t\t\tvar b = indices[ i + 1 ];\n\n\t\t\t\t\t\tvStart.fromArray( positions, a * 3 );\n\t\t\t\t\t\tvEnd.fromArray( positions, b * 3 );\n\n\t\t\t\t\t\tvar distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment );\n\n\t\t\t\t\t\tif ( distSq > precisionSq ) continue;\n\n\t\t\t\t\t\tinterRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation\n\n\t\t\t\t\t\tvar distance = raycaster.ray.origin.distanceTo( interRay );\n\n\t\t\t\t\t\tif ( distance < raycaster.near || distance > raycaster.far ) continue;\n\n\t\t\t\t\t\tintersects.push( {\n\n\t\t\t\t\t\t\tdistance: distance,\n\t\t\t\t\t\t\t// What do we want? intersection point on the ray or on the segment??\n\t\t\t\t\t\t\t// point: raycaster.ray.at( distance ),\n\t\t\t\t\t\t\tpoint: interSegment.clone().applyMatrix4( this.matrixWorld ),\n\t\t\t\t\t\t\tindex: i,\n\t\t\t\t\t\t\tface: null,\n\t\t\t\t\t\t\tfaceIndex: null,\n\t\t\t\t\t\t\tobject: this\n\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tfor ( var i = 0, l = positions.length / 3 - 1; i < l; i += step ) {\n\n\t\t\t\t\t\tvStart.fromArray( positions, 3 * i );\n\t\t\t\t\t\tvEnd.fromArray( positions, 3 * i + 3 );\n\n\t\t\t\t\t\tvar distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment );\n\n\t\t\t\t\t\tif ( distSq > precisionSq ) continue;\n\n\t\t\t\t\t\tinterRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation\n\n\t\t\t\t\t\tvar distance = raycaster.ray.origin.distanceTo( interRay );\n\n\t\t\t\t\t\tif ( distance < raycaster.near || distance > raycaster.far ) continue;\n\n\t\t\t\t\t\tintersects.push( {\n\n\t\t\t\t\t\t\tdistance: distance,\n\t\t\t\t\t\t\t// What do we want? intersection point on the ray or on the segment??\n\t\t\t\t\t\t\t// point: raycaster.ray.at( distance ),\n\t\t\t\t\t\t\tpoint: interSegment.clone().applyMatrix4( this.matrixWorld ),\n\t\t\t\t\t\t\tindex: i,\n\t\t\t\t\t\t\tface: null,\n\t\t\t\t\t\t\tfaceIndex: null,\n\t\t\t\t\t\t\tobject: this\n\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else if ( geometry.isGeometry ) {\n\n\t\t\t\tvar vertices = geometry.vertices;\n\t\t\t\tvar nbVertices = vertices.length;\n\n\t\t\t\tfor ( var i = 0; i < nbVertices - 1; i += step ) {\n\n\t\t\t\t\tvar distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment );\n\n\t\t\t\t\tif ( distSq > precisionSq ) continue;\n\n\t\t\t\t\tinterRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation\n\n\t\t\t\t\tvar distance = raycaster.ray.origin.distanceTo( interRay );\n\n\t\t\t\t\tif ( distance < raycaster.near || distance > raycaster.far ) continue;\n\n\t\t\t\t\tintersects.push( {\n\n\t\t\t\t\t\tdistance: distance,\n\t\t\t\t\t\t// What do we want? intersection point on the ray or on the segment??\n\t\t\t\t\t\t// point: raycaster.ray.at( distance ),\n\t\t\t\t\t\tpoint: interSegment.clone().applyMatrix4( this.matrixWorld ),\n\t\t\t\t\t\tindex: i,\n\t\t\t\t\t\tface: null,\n\t\t\t\t\t\tfaceIndex: null,\n\t\t\t\t\t\tobject: this\n\n\t\t\t\t\t} );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t}() ),\n\n\tclone: function () {\n\n\t\treturn new this.constructor( this.geometry, this.material ).copy( this );\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction LineSegments( geometry, material ) {\n\n\tLine.call( this, geometry, material );\n\n\tthis.type = 'LineSegments';\n\n}\n\nLineSegments.prototype = Object.assign( Object.create( Line.prototype ), {\n\n\tconstructor: LineSegments,\n\n\tisLineSegments: true\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author alteredq / http://alteredqualia.com/\n *\n * parameters = {\n * color: ,\n * opacity: ,\n * map: new THREE.Texture( ),\n *\n * size: ,\n * sizeAttenuation: \n * }\n */\n\nfunction PointsMaterial( parameters ) {\n\n\tMaterial.call( this );\n\n\tthis.type = 'PointsMaterial';\n\n\tthis.color = new Color( 0xffffff );\n\n\tthis.map = null;\n\n\tthis.size = 1;\n\tthis.sizeAttenuation = true;\n\n\tthis.lights = false;\n\n\tthis.setValues( parameters );\n\n}\n\nPointsMaterial.prototype = Object.create( Material.prototype );\nPointsMaterial.prototype.constructor = PointsMaterial;\n\nPointsMaterial.prototype.isPointsMaterial = true;\n\nPointsMaterial.prototype.copy = function ( source ) {\n\n\tMaterial.prototype.copy.call( this, source );\n\n\tthis.color.copy( source.color );\n\n\tthis.map = source.map;\n\n\tthis.size = source.size;\n\tthis.sizeAttenuation = source.sizeAttenuation;\n\n\treturn this;\n\n};\n\n/**\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction Points( geometry, material ) {\n\n\tObject3D.call( this );\n\n\tthis.type = 'Points';\n\n\tthis.geometry = geometry !== undefined ? geometry : new BufferGeometry();\n\tthis.material = material !== undefined ? material : new PointsMaterial( { color: Math.random() * 0xffffff } );\n\n}\n\nPoints.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\tconstructor: Points,\n\n\tisPoints: true,\n\n\traycast: ( function () {\n\n\t\tvar inverseMatrix = new Matrix4();\n\t\tvar ray = new Ray();\n\t\tvar sphere = new Sphere();\n\n\t\treturn function raycast( raycaster, intersects ) {\n\n\t\t\tvar object = this;\n\t\t\tvar geometry = this.geometry;\n\t\t\tvar matrixWorld = this.matrixWorld;\n\t\t\tvar threshold = raycaster.params.Points.threshold;\n\n\t\t\t// Checking boundingSphere distance to ray\n\n\t\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\n\n\t\t\tsphere.copy( geometry.boundingSphere );\n\t\t\tsphere.applyMatrix4( matrixWorld );\n\n\t\t\tif ( raycaster.ray.intersectsSphere( sphere ) === false ) return;\n\n\t\t\t//\n\n\t\t\tinverseMatrix.getInverse( matrixWorld );\n\t\t\tray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );\n\n\t\t\tvar localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );\n\t\t\tvar localThresholdSq = localThreshold * localThreshold;\n\t\t\tvar position = new Vector3();\n\n\t\t\tfunction testPoint( point, index ) {\n\n\t\t\t\tvar rayPointDistanceSq = ray.distanceSqToPoint( point );\n\n\t\t\t\tif ( rayPointDistanceSq < localThresholdSq ) {\n\n\t\t\t\t\tvar intersectPoint = ray.closestPointToPoint( point );\n\t\t\t\t\tintersectPoint.applyMatrix4( matrixWorld );\n\n\t\t\t\t\tvar distance = raycaster.ray.origin.distanceTo( intersectPoint );\n\n\t\t\t\t\tif ( distance < raycaster.near || distance > raycaster.far ) return;\n\n\t\t\t\t\tintersects.push( {\n\n\t\t\t\t\t\tdistance: distance,\n\t\t\t\t\t\tdistanceToRay: Math.sqrt( rayPointDistanceSq ),\n\t\t\t\t\t\tpoint: intersectPoint.clone(),\n\t\t\t\t\t\tindex: index,\n\t\t\t\t\t\tface: null,\n\t\t\t\t\t\tobject: object\n\n\t\t\t\t\t} );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( geometry.isBufferGeometry ) {\n\n\t\t\t\tvar index = geometry.index;\n\t\t\t\tvar attributes = geometry.attributes;\n\t\t\t\tvar positions = attributes.position.array;\n\n\t\t\t\tif ( index !== null ) {\n\n\t\t\t\t\tvar indices = index.array;\n\n\t\t\t\t\tfor ( var i = 0, il = indices.length; i < il; i ++ ) {\n\n\t\t\t\t\t\tvar a = indices[ i ];\n\n\t\t\t\t\t\tposition.fromArray( positions, a * 3 );\n\n\t\t\t\t\t\ttestPoint( position, a );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tfor ( var i = 0, l = positions.length / 3; i < l; i ++ ) {\n\n\t\t\t\t\t\tposition.fromArray( positions, i * 3 );\n\n\t\t\t\t\t\ttestPoint( position, i );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tvar vertices = geometry.vertices;\n\n\t\t\t\tfor ( var i = 0, l = vertices.length; i < l; i ++ ) {\n\n\t\t\t\t\ttestPoint( vertices[ i ], i );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t}() ),\n\n\tclone: function () {\n\n\t\treturn new this.constructor( this.geometry, this.material ).copy( this );\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction Group() {\n\n\tObject3D.call( this );\n\n\tthis.type = 'Group';\n\n}\n\nGroup.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\tconstructor: Group\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction VideoTexture( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {\n\n\tTexture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );\n\n\tthis.generateMipmaps = false;\n\n\tvar scope = this;\n\n\tfunction update() {\n\n\t\trequestAnimationFrame( update );\n\n\t\tif ( video.readyState >= video.HAVE_CURRENT_DATA ) {\n\n\t\t\tscope.needsUpdate = true;\n\n\t\t}\n\n\t}\n\n\tupdate();\n\n}\n\nVideoTexture.prototype = Object.create( Texture.prototype );\nVideoTexture.prototype.constructor = VideoTexture;\n\n/**\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction CompressedTexture( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {\n\n\tTexture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );\n\n\tthis.image = { width: width, height: height };\n\tthis.mipmaps = mipmaps;\n\n\t// no flipping for cube textures\n\t// (also flipping doesn't work for compressed textures )\n\n\tthis.flipY = false;\n\n\t// can't generate mipmaps for compressed textures\n\t// mips must be embedded in DDS files\n\n\tthis.generateMipmaps = false;\n\n}\n\nCompressedTexture.prototype = Object.create( Texture.prototype );\nCompressedTexture.prototype.constructor = CompressedTexture;\n\nCompressedTexture.prototype.isCompressedTexture = true;\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {\n\n\tTexture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );\n\n\tthis.needsUpdate = true;\n\n}\n\nCanvasTexture.prototype = Object.create( Texture.prototype );\nCanvasTexture.prototype.constructor = CanvasTexture;\n\n/**\n * @author Matt DesLauriers / @mattdesl\n * @author atix / arthursilber.de\n */\n\nfunction DepthTexture( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) {\n\n\tformat = format !== undefined ? format : DepthFormat;\n\n\tif ( format !== DepthFormat && format !== DepthStencilFormat ) {\n\n\t\tthrow new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' )\n\n\t}\n\n\tif ( type === undefined && format === DepthFormat ) type = UnsignedShortType;\n\tif ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type;\n\n\tTexture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );\n\n\tthis.image = { width: width, height: height };\n\n\tthis.magFilter = magFilter !== undefined ? magFilter : NearestFilter;\n\tthis.minFilter = minFilter !== undefined ? minFilter : NearestFilter;\n\n\tthis.flipY = false;\n\tthis.generateMipmaps\t= false;\n\n}\n\nDepthTexture.prototype = Object.create( Texture.prototype );\nDepthTexture.prototype.constructor = DepthTexture;\nDepthTexture.prototype.isDepthTexture = true;\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction WireframeGeometry( geometry ) {\n\n\tBufferGeometry.call( this );\n\n\tthis.type = 'WireframeGeometry';\n\n\t// buffer\n\n\tvar vertices = [];\n\n\t// helper variables\n\n\tvar i, j, l, o, ol;\n\tvar edge = [ 0, 0 ], edges = {}, e;\n\tvar key, keys = [ 'a', 'b', 'c' ];\n\tvar vertex;\n\n\t// different logic for Geometry and BufferGeometry\n\n\tif ( geometry && geometry.isGeometry ) {\n\n\t\t// create a data structure that contains all edges without duplicates\n\n\t\tvar faces = geometry.faces;\n\n\t\tfor ( i = 0, l = faces.length; i < l; i ++ ) {\n\n\t\t\tvar face = faces[ i ];\n\n\t\t\tfor ( j = 0; j < 3; j ++ ) {\n\n\t\t\t\tedge[ 0 ] = face[ keys[ j ] ];\n\t\t\t\tedge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ];\n\t\t\t\tedge.sort( sortFunction ); // sorting prevents duplicates\n\n\t\t\t\tkey = edge.toString();\n\n\t\t\t\tif ( edges[ key ] === undefined ) {\n\n\t\t\t\t\tedges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t// generate vertices\n\n\t\tfor ( key in edges ) {\n\n\t\t\te = edges[ key ];\n\n\t\t\tvertex = geometry.vertices[ e.index1 ];\n\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\tvertex = geometry.vertices[ e.index2 ];\n\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t}\n\n\t} else if ( geometry && geometry.isBufferGeometry ) {\n\n\t\tvar position, indices, groups;\n\t\tvar group, start, count;\n\t\tvar index1, index2;\n\n\t\tvertex = new Vector3();\n\n\t\tif ( geometry.index !== null ) {\n\n\t\t\t// indexed BufferGeometry\n\n\t\t\tposition = geometry.attributes.position;\n\t\t\tindices = geometry.index;\n\t\t\tgroups = geometry.groups;\n\n\t\t\tif ( groups.length === 0 ) {\n\n\t\t\t\tgeometry.addGroup( 0, indices.count );\n\n\t\t\t}\n\n\t\t\t// create a data structure that contains all eges without duplicates\n\n\t\t\tfor ( o = 0, ol = groups.length; o < ol; ++ o ) {\n\n\t\t\t\tgroup = groups[ o ];\n\n\t\t\t\tstart = group.start;\n\t\t\t\tcount = group.count;\n\n\t\t\t\tfor ( i = start, l = ( start + count ); i < l; i += 3 ) {\n\n\t\t\t\t\tfor ( j = 0; j < 3; j ++ ) {\n\n\t\t\t\t\t\tedge[ 0 ] = indices.getX( i + j );\n\t\t\t\t\t\tedge[ 1 ] = indices.getX( i + ( j + 1 ) % 3 );\n\t\t\t\t\t\tedge.sort( sortFunction ); // sorting prevents duplicates\n\n\t\t\t\t\t\tkey = edge.toString();\n\n\t\t\t\t\t\tif ( edges[ key ] === undefined ) {\n\n\t\t\t\t\t\t\tedges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// generate vertices\n\n\t\t\tfor ( key in edges ) {\n\n\t\t\t\te = edges[ key ];\n\n\t\t\t\tvertex.fromBufferAttribute( position, e.index1 );\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\tvertex.fromBufferAttribute( position, e.index2 );\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// non-indexed BufferGeometry\n\n\t\t\tposition = geometry.attributes.position;\n\n\t\t\tfor ( i = 0, l = ( position.count / 3 ); i < l; i ++ ) {\n\n\t\t\t\tfor ( j = 0; j < 3; j ++ ) {\n\n\t\t\t\t\t// three edges per triangle, an edge is represented as (index1, index2)\n\t\t\t\t\t// e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)\n\n\t\t\t\t\tindex1 = 3 * i + j;\n\t\t\t\t\tvertex.fromBufferAttribute( position, index1 );\n\t\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t\tindex2 = 3 * i + ( ( j + 1 ) % 3 );\n\t\t\t\t\tvertex.fromBufferAttribute( position, index2 );\n\t\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t// build geometry\n\n\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\n\t// custom array sort function\n\n\tfunction sortFunction( a, b ) {\n\n\t\treturn a - b;\n\n\t}\n\n}\n\nWireframeGeometry.prototype = Object.create( BufferGeometry.prototype );\nWireframeGeometry.prototype.constructor = WireframeGeometry;\n\n/**\n * @author zz85 / https://github.com/zz85\n *\n * Parametric Surfaces Geometry\n * based on the brilliant article by @prideout http://prideout.net/blog/?p=44\n */\n\nfunction ParametricGeometry( func, slices, stacks ) {\n\n\tGeometry.call( this );\n\n\tthis.type = 'ParametricGeometry';\n\n\tthis.parameters = {\n\t\tfunc: func,\n\t\tslices: slices,\n\t\tstacks: stacks\n\t};\n\n\tthis.fromBufferGeometry( new ParametricBufferGeometry( func, slices, stacks ) );\n\tthis.mergeVertices();\n\n}\n\nParametricGeometry.prototype = Object.create( Geometry.prototype );\nParametricGeometry.prototype.constructor = ParametricGeometry;\n\n/**\n * @author Mugen87 / https://github.com/Mugen87\n *\n * Parametric Surfaces Geometry\n * based on the brilliant article by @prideout http://prideout.net/blog/?p=44\n */\n\nfunction ParametricBufferGeometry( func, slices, stacks ) {\n\n\tBufferGeometry.call( this );\n\n\tthis.type = 'ParametricBufferGeometry';\n\n\tthis.parameters = {\n\t\tfunc: func,\n\t\tslices: slices,\n\t\tstacks: stacks\n\t};\n\n\t// buffers\n\n\tvar indices = [];\n\tvar vertices = [];\n\tvar uvs = [];\n\n\tvar i, j;\n\n\t// generate vertices and uvs\n\n\tvar sliceCount = slices + 1;\n\n\tfor ( i = 0; i <= stacks; i ++ ) {\n\n\t\tvar v = i / stacks;\n\n\t\tfor ( j = 0; j <= slices; j ++ ) {\n\n\t\t\tvar u = j / slices;\n\n\t\t\tvar p = func( u, v );\n\t\t\tvertices.push( p.x, p.y, p.z );\n\n\t\t\tuvs.push( u, v );\n\n\t\t}\n\n\t}\n\n\t// generate indices\n\n\tfor ( i = 0; i < stacks; i ++ ) {\n\n\t\tfor ( j = 0; j < slices; j ++ ) {\n\n\t\t\tvar a = i * sliceCount + j;\n\t\t\tvar b = i * sliceCount + j + 1;\n\t\t\tvar c = ( i + 1 ) * sliceCount + j + 1;\n\t\t\tvar d = ( i + 1 ) * sliceCount + j;\n\n\t\t\t// faces one and two\n\n\t\t\tindices.push( a, b, d );\n\t\t\tindices.push( b, c, d );\n\n\t\t}\n\n\t}\n\n\t// build geometry\n\n\tthis.setIndex( indices );\n\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t// generate normals\n\n\tthis.computeVertexNormals();\n\n}\n\nParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\nParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry;\n\n/**\n * @author clockworkgeek / https://github.com/clockworkgeek\n * @author timothypratley / https://github.com/timothypratley\n * @author WestLangley / http://github.com/WestLangley\n*/\n\nfunction PolyhedronGeometry( vertices, indices, radius, detail ) {\n\n\tGeometry.call( this );\n\n\tthis.type = 'PolyhedronGeometry';\n\n\tthis.parameters = {\n\t\tvertices: vertices,\n\t\tindices: indices,\n\t\tradius: radius,\n\t\tdetail: detail\n\t};\n\n\tthis.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) );\n\tthis.mergeVertices();\n\n}\n\nPolyhedronGeometry.prototype = Object.create( Geometry.prototype );\nPolyhedronGeometry.prototype.constructor = PolyhedronGeometry;\n\n/**\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction PolyhedronBufferGeometry( vertices, indices, radius, detail ) {\n\n\tBufferGeometry.call( this );\n\n\tthis.type = 'PolyhedronBufferGeometry';\n\n\tthis.parameters = {\n\t\tvertices: vertices,\n\t\tindices: indices,\n\t\tradius: radius,\n\t\tdetail: detail\n\t};\n\n\tradius = radius || 1;\n\tdetail = detail || 0;\n\n\t// default buffer data\n\n\tvar vertexBuffer = [];\n\tvar uvBuffer = [];\n\n\t// the subdivision creates the vertex buffer data\n\n\tsubdivide( detail );\n\n\t// all vertices should lie on a conceptual sphere with a given radius\n\n\tappplyRadius( radius );\n\n\t// finally, create the uv data\n\n\tgenerateUVs();\n\n\t// build non-indexed geometry\n\n\tthis.addAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );\n\tthis.addAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );\n\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );\n\tthis.normalizeNormals();\n\n\t// helper functions\n\n\tfunction subdivide( detail ) {\n\n\t\tvar a = new Vector3();\n\t\tvar b = new Vector3();\n\t\tvar c = new Vector3();\n\n\t\t// iterate over all faces and apply a subdivison with the given detail value\n\n\t\tfor ( var i = 0; i < indices.length; i += 3 ) {\n\n\t\t\t// get the vertices of the face\n\n\t\t\tgetVertexByIndex( indices[ i + 0 ], a );\n\t\t\tgetVertexByIndex( indices[ i + 1 ], b );\n\t\t\tgetVertexByIndex( indices[ i + 2 ], c );\n\n\t\t\t// perform subdivision\n\n\t\t\tsubdivideFace( a, b, c, detail );\n\n\t\t}\n\n\t}\n\n\tfunction subdivideFace( a, b, c, detail ) {\n\n\t\tvar cols = Math.pow( 2, detail );\n\n\t\t// we use this multidimensional array as a data structure for creating the subdivision\n\n\t\tvar v = [];\n\n\t\tvar i, j;\n\n\t\t// construct all of the vertices for this subdivision\n\n\t\tfor ( i = 0; i <= cols; i ++ ) {\n\n\t\t\tv[ i ] = [];\n\n\t\t\tvar aj = a.clone().lerp( c, i / cols );\n\t\t\tvar bj = b.clone().lerp( c, i / cols );\n\n\t\t\tvar rows = cols - i;\n\n\t\t\tfor ( j = 0; j <= rows; j ++ ) {\n\n\t\t\t\tif ( j === 0 && i === cols ) {\n\n\t\t\t\t\tv[ i ][ j ] = aj;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tv[ i ][ j ] = aj.clone().lerp( bj, j / rows );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t// construct all of the faces\n\n\t\tfor ( i = 0; i < cols; i ++ ) {\n\n\t\t\tfor ( j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {\n\n\t\t\t\tvar k = Math.floor( j / 2 );\n\n\t\t\t\tif ( j % 2 === 0 ) {\n\n\t\t\t\t\tpushVertex( v[ i ][ k + 1 ] );\n\t\t\t\t\tpushVertex( v[ i + 1 ][ k ] );\n\t\t\t\t\tpushVertex( v[ i ][ k ] );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tpushVertex( v[ i ][ k + 1 ] );\n\t\t\t\t\tpushVertex( v[ i + 1 ][ k + 1 ] );\n\t\t\t\t\tpushVertex( v[ i + 1 ][ k ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction appplyRadius( radius ) {\n\n\t\tvar vertex = new Vector3();\n\n\t\t// iterate over the entire buffer and apply the radius to each vertex\n\n\t\tfor ( var i = 0; i < vertexBuffer.length; i += 3 ) {\n\n\t\t\tvertex.x = vertexBuffer[ i + 0 ];\n\t\t\tvertex.y = vertexBuffer[ i + 1 ];\n\t\t\tvertex.z = vertexBuffer[ i + 2 ];\n\n\t\t\tvertex.normalize().multiplyScalar( radius );\n\n\t\t\tvertexBuffer[ i + 0 ] = vertex.x;\n\t\t\tvertexBuffer[ i + 1 ] = vertex.y;\n\t\t\tvertexBuffer[ i + 2 ] = vertex.z;\n\n\t\t}\n\n\t}\n\n\tfunction generateUVs() {\n\n\t\tvar vertex = new Vector3();\n\n\t\tfor ( var i = 0; i < vertexBuffer.length; i += 3 ) {\n\n\t\t\tvertex.x = vertexBuffer[ i + 0 ];\n\t\t\tvertex.y = vertexBuffer[ i + 1 ];\n\t\t\tvertex.z = vertexBuffer[ i + 2 ];\n\n\t\t\tvar u = azimuth( vertex ) / 2 / Math.PI + 0.5;\n\t\t\tvar v = inclination( vertex ) / Math.PI + 0.5;\n\t\t\tuvBuffer.push( u, 1 - v );\n\n\t\t}\n\n\t\tcorrectUVs();\n\n\t\tcorrectSeam();\n\n\t}\n\n\tfunction correctSeam() {\n\n\t\t// handle case when face straddles the seam, see #3269\n\n\t\tfor ( var i = 0; i < uvBuffer.length; i += 6 ) {\n\n\t\t\t// uv data of a single face\n\n\t\t\tvar x0 = uvBuffer[ i + 0 ];\n\t\t\tvar x1 = uvBuffer[ i + 2 ];\n\t\t\tvar x2 = uvBuffer[ i + 4 ];\n\n\t\t\tvar max = Math.max( x0, x1, x2 );\n\t\t\tvar min = Math.min( x0, x1, x2 );\n\n\t\t\t// 0.9 is somewhat arbitrary\n\n\t\t\tif ( max > 0.9 && min < 0.1 ) {\n\n\t\t\t\tif ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;\n\t\t\t\tif ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;\n\t\t\t\tif ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction pushVertex( vertex ) {\n\n\t\tvertexBuffer.push( vertex.x, vertex.y, vertex.z );\n\n\t}\n\n\tfunction getVertexByIndex( index, vertex ) {\n\n\t\tvar stride = index * 3;\n\n\t\tvertex.x = vertices[ stride + 0 ];\n\t\tvertex.y = vertices[ stride + 1 ];\n\t\tvertex.z = vertices[ stride + 2 ];\n\n\t}\n\n\tfunction correctUVs() {\n\n\t\tvar a = new Vector3();\n\t\tvar b = new Vector3();\n\t\tvar c = new Vector3();\n\n\t\tvar centroid = new Vector3();\n\n\t\tvar uvA = new Vector2();\n\t\tvar uvB = new Vector2();\n\t\tvar uvC = new Vector2();\n\n\t\tfor ( var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {\n\n\t\t\ta.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );\n\t\t\tb.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );\n\t\t\tc.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );\n\n\t\t\tuvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );\n\t\t\tuvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );\n\t\t\tuvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );\n\n\t\t\tcentroid.copy( a ).add( b ).add( c ).divideScalar( 3 );\n\n\t\t\tvar azi = azimuth( centroid );\n\n\t\t\tcorrectUV( uvA, j + 0, a, azi );\n\t\t\tcorrectUV( uvB, j + 2, b, azi );\n\t\t\tcorrectUV( uvC, j + 4, c, azi );\n\n\t\t}\n\n\t}\n\n\tfunction correctUV( uv, stride, vector, azimuth ) {\n\n\t\tif ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {\n\n\t\t\tuvBuffer[ stride ] = uv.x - 1;\n\n\t\t}\n\n\t\tif ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {\n\n\t\t\tuvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;\n\n\t\t}\n\n\t}\n\n\t// Angle around the Y axis, counter-clockwise when looking from above.\n\n\tfunction azimuth( vector ) {\n\n\t\treturn Math.atan2( vector.z, - vector.x );\n\n\t}\n\n\n\t// Angle above the XZ plane.\n\n\tfunction inclination( vector ) {\n\n\t\treturn Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );\n\n\t}\n\n}\n\nPolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\nPolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry;\n\n/**\n * @author timothypratley / https://github.com/timothypratley\n */\n\nfunction TetrahedronGeometry( radius, detail ) {\n\n\tGeometry.call( this );\n\n\tthis.type = 'TetrahedronGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\tdetail: detail\n\t};\n\n\tthis.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) );\n\tthis.mergeVertices();\n\n}\n\nTetrahedronGeometry.prototype = Object.create( Geometry.prototype );\nTetrahedronGeometry.prototype.constructor = TetrahedronGeometry;\n\n/**\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction TetrahedronBufferGeometry( radius, detail ) {\n\n\tvar vertices = [\n\t\t1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1\n\t];\n\n\tvar indices = [\n\t\t2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1\n\t];\n\n\tPolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );\n\n\tthis.type = 'TetrahedronBufferGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\tdetail: detail\n\t};\n\n}\n\nTetrahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );\nTetrahedronBufferGeometry.prototype.constructor = TetrahedronBufferGeometry;\n\n/**\n * @author timothypratley / https://github.com/timothypratley\n */\n\nfunction OctahedronGeometry( radius, detail ) {\n\n\tGeometry.call( this );\n\n\tthis.type = 'OctahedronGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\tdetail: detail\n\t};\n\n\tthis.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) );\n\tthis.mergeVertices();\n\n}\n\nOctahedronGeometry.prototype = Object.create( Geometry.prototype );\nOctahedronGeometry.prototype.constructor = OctahedronGeometry;\n\n/**\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction OctahedronBufferGeometry( radius, detail ) {\n\n\tvar vertices = [\n\t\t1, 0, 0, - 1, 0, 0, 0, 1, 0, 0, - 1, 0, 0, 0, 1, 0, 0, - 1\n\t];\n\n\tvar indices = [\n\t\t0, 2, 4, 0, 4, 3, 0, 3, 5, 0, 5, 2, 1, 2, 5, 1, 5, 3, 1, 3, 4, 1, 4, 2\n\t];\n\n\tPolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );\n\n\tthis.type = 'OctahedronBufferGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\tdetail: detail\n\t};\n\n}\n\nOctahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );\nOctahedronBufferGeometry.prototype.constructor = OctahedronBufferGeometry;\n\n/**\n * @author timothypratley / https://github.com/timothypratley\n */\n\nfunction IcosahedronGeometry( radius, detail ) {\n\n \tGeometry.call( this );\n\n\tthis.type = 'IcosahedronGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\tdetail: detail\n\t};\n\n\tthis.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) );\n\tthis.mergeVertices();\n\n}\n\nIcosahedronGeometry.prototype = Object.create( Geometry.prototype );\nIcosahedronGeometry.prototype.constructor = IcosahedronGeometry;\n\n/**\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction IcosahedronBufferGeometry( radius, detail ) {\n\n\tvar t = ( 1 + Math.sqrt( 5 ) ) / 2;\n\n\tvar vertices = [\n\t\t- 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0,\n\t\t 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t,\n\t\t t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1\n\t];\n\n\tvar indices = [\n\t\t 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11,\n\t\t 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8,\n\t\t 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9,\n\t\t 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1\n\t];\n\n\tPolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );\n\n\tthis.type = 'IcosahedronBufferGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\tdetail: detail\n\t};\n\n}\n\nIcosahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );\nIcosahedronBufferGeometry.prototype.constructor = IcosahedronBufferGeometry;\n\n/**\n * @author Abe Pazos / https://hamoid.com\n */\n\nfunction DodecahedronGeometry( radius, detail ) {\n\n\tGeometry.call( this );\n\n\tthis.type = 'DodecahedronGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\tdetail: detail\n\t};\n\n\tthis.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) );\n\tthis.mergeVertices();\n\n}\n\nDodecahedronGeometry.prototype = Object.create( Geometry.prototype );\nDodecahedronGeometry.prototype.constructor = DodecahedronGeometry;\n\n/**\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction DodecahedronBufferGeometry( radius, detail ) {\n\n\tvar t = ( 1 + Math.sqrt( 5 ) ) / 2;\n\tvar r = 1 / t;\n\n\tvar vertices = [\n\n\t\t// (±1, ±1, ±1)\n\t\t- 1, - 1, - 1, - 1, - 1, 1,\n\t\t- 1, 1, - 1, - 1, 1, 1,\n\t\t 1, - 1, - 1, 1, - 1, 1,\n\t\t 1, 1, - 1, 1, 1, 1,\n\n\t\t// (0, ±1/φ, ±φ)\n\t\t 0, - r, - t, 0, - r, t,\n\t\t 0, r, - t, 0, r, t,\n\n\t\t// (±1/φ, ±φ, 0)\n\t\t- r, - t, 0, - r, t, 0,\n\t\t r, - t, 0, r, t, 0,\n\n\t\t// (±φ, 0, ±1/φ)\n\t\t- t, 0, - r, t, 0, - r,\n\t\t- t, 0, r, t, 0, r\n\t];\n\n\tvar indices = [\n\t\t 3, 11, 7, 3, 7, 15, 3, 15, 13,\n\t\t 7, 19, 17, 7, 17, 6, 7, 6, 15,\n\t\t17, 4, 8, 17, 8, 10, 17, 10, 6,\n\t\t 8, 0, 16, 8, 16, 2, 8, 2, 10,\n\t\t 0, 12, 1, 0, 1, 18, 0, 18, 16,\n\t\t 6, 10, 2, 6, 2, 13, 6, 13, 15,\n\t\t 2, 16, 18, 2, 18, 3, 2, 3, 13,\n\t\t18, 1, 9, 18, 9, 11, 18, 11, 3,\n\t\t 4, 14, 12, 4, 12, 0, 4, 0, 8,\n\t\t11, 9, 5, 11, 5, 19, 11, 19, 7,\n\t\t19, 5, 14, 19, 14, 4, 19, 4, 17,\n\t\t 1, 12, 14, 1, 14, 5, 1, 5, 9\n\t];\n\n\tPolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );\n\n\tthis.type = 'DodecahedronBufferGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\tdetail: detail\n\t};\n\n}\n\nDodecahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );\nDodecahedronBufferGeometry.prototype.constructor = DodecahedronBufferGeometry;\n\n/**\n * @author oosmoxiecode / https://github.com/oosmoxiecode\n * @author WestLangley / https://github.com/WestLangley\n * @author zz85 / https://github.com/zz85\n * @author miningold / https://github.com/miningold\n * @author jonobr1 / https://github.com/jonobr1\n *\n * Creates a tube which extrudes along a 3d spline.\n */\n\nfunction TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) {\n\n\tGeometry.call( this );\n\n\tthis.type = 'TubeGeometry';\n\n\tthis.parameters = {\n\t\tpath: path,\n\t\ttubularSegments: tubularSegments,\n\t\tradius: radius,\n\t\tradialSegments: radialSegments,\n\t\tclosed: closed\n\t};\n\n\tif ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' );\n\n\tvar bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed );\n\n\t// expose internals\n\n\tthis.tangents = bufferGeometry.tangents;\n\tthis.normals = bufferGeometry.normals;\n\tthis.binormals = bufferGeometry.binormals;\n\n\t// create geometry\n\n\tthis.fromBufferGeometry( bufferGeometry );\n\tthis.mergeVertices();\n\n}\n\nTubeGeometry.prototype = Object.create( Geometry.prototype );\nTubeGeometry.prototype.constructor = TubeGeometry;\n\n/**\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) {\n\n\tBufferGeometry.call( this );\n\n\tthis.type = 'TubeBufferGeometry';\n\n\tthis.parameters = {\n\t\tpath: path,\n\t\ttubularSegments: tubularSegments,\n\t\tradius: radius,\n\t\tradialSegments: radialSegments,\n\t\tclosed: closed\n\t};\n\n\ttubularSegments = tubularSegments || 64;\n\tradius = radius || 1;\n\tradialSegments = radialSegments || 8;\n\tclosed = closed || false;\n\n\tvar frames = path.computeFrenetFrames( tubularSegments, closed );\n\n\t// expose internals\n\n\tthis.tangents = frames.tangents;\n\tthis.normals = frames.normals;\n\tthis.binormals = frames.binormals;\n\n\t// helper variables\n\n\tvar vertex = new Vector3();\n\tvar normal = new Vector3();\n\tvar uv = new Vector2();\n\n\tvar i, j;\n\n\t// buffer\n\n\tvar vertices = [];\n\tvar normals = [];\n\tvar uvs = [];\n\tvar indices = [];\n\n\t// create buffer data\n\n\tgenerateBufferData();\n\n\t// build geometry\n\n\tthis.setIndex( indices );\n\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t// functions\n\n\tfunction generateBufferData() {\n\n\t\tfor ( i = 0; i < tubularSegments; i ++ ) {\n\n\t\t\tgenerateSegment( i );\n\n\t\t}\n\n\t\t// if the geometry is not closed, generate the last row of vertices and normals\n\t\t// at the regular position on the given path\n\t\t//\n\t\t// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)\n\n\t\tgenerateSegment( ( closed === false ) ? tubularSegments : 0 );\n\n\t\t// uvs are generated in a separate function.\n\t\t// this makes it easy compute correct values for closed geometries\n\n\t\tgenerateUVs();\n\n\t\t// finally create faces\n\n\t\tgenerateIndices();\n\n\t}\n\n\tfunction generateSegment( i ) {\n\n\t\t// we use getPointAt to sample evenly distributed points from the given path\n\n\t\tvar P = path.getPointAt( i / tubularSegments );\n\n\t\t// retrieve corresponding normal and binormal\n\n\t\tvar N = frames.normals[ i ];\n\t\tvar B = frames.binormals[ i ];\n\n\t\t// generate normals and vertices for the current segment\n\n\t\tfor ( j = 0; j <= radialSegments; j ++ ) {\n\n\t\t\tvar v = j / radialSegments * Math.PI * 2;\n\n\t\t\tvar sin = Math.sin( v );\n\t\t\tvar cos = - Math.cos( v );\n\n\t\t\t// normal\n\n\t\t\tnormal.x = ( cos * N.x + sin * B.x );\n\t\t\tnormal.y = ( cos * N.y + sin * B.y );\n\t\t\tnormal.z = ( cos * N.z + sin * B.z );\n\t\t\tnormal.normalize();\n\n\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t// vertex\n\n\t\t\tvertex.x = P.x + radius * normal.x;\n\t\t\tvertex.y = P.y + radius * normal.y;\n\t\t\tvertex.z = P.z + radius * normal.z;\n\n\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t}\n\n\t}\n\n\tfunction generateIndices() {\n\n\t\tfor ( j = 1; j <= tubularSegments; j ++ ) {\n\n\t\t\tfor ( i = 1; i <= radialSegments; i ++ ) {\n\n\t\t\t\tvar a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );\n\t\t\t\tvar b = ( radialSegments + 1 ) * j + ( i - 1 );\n\t\t\t\tvar c = ( radialSegments + 1 ) * j + i;\n\t\t\t\tvar d = ( radialSegments + 1 ) * ( j - 1 ) + i;\n\n\t\t\t\t// faces\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction generateUVs() {\n\n\t\tfor ( i = 0; i <= tubularSegments; i ++ ) {\n\n\t\t\tfor ( j = 0; j <= radialSegments; j ++ ) {\n\n\t\t\t\tuv.x = i / tubularSegments;\n\t\t\t\tuv.y = j / radialSegments;\n\n\t\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n\nTubeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\nTubeBufferGeometry.prototype.constructor = TubeBufferGeometry;\n\n/**\n * @author oosmoxiecode\n */\n\nfunction TorusKnotGeometry( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) {\n\n\tGeometry.call( this );\n\n\tthis.type = 'TorusKnotGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\ttube: tube,\n\t\ttubularSegments: tubularSegments,\n\t\tradialSegments: radialSegments,\n\t\tp: p,\n\t\tq: q\n\t};\n\n\tif ( heightScale !== undefined ) console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' );\n\n\tthis.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) );\n\tthis.mergeVertices();\n\n}\n\nTorusKnotGeometry.prototype = Object.create( Geometry.prototype );\nTorusKnotGeometry.prototype.constructor = TorusKnotGeometry;\n\n/**\n * @author Mugen87 / https://github.com/Mugen87\n * see: http://www.blackpawn.com/texts/pqtorus/\n */\n\nfunction TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) {\n\n\tBufferGeometry.call( this );\n\n\tthis.type = 'TorusKnotBufferGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\ttube: tube,\n\t\ttubularSegments: tubularSegments,\n\t\tradialSegments: radialSegments,\n\t\tp: p,\n\t\tq: q\n\t};\n\n\tradius = radius || 100;\n\ttube = tube || 40;\n\ttubularSegments = Math.floor( tubularSegments ) || 64;\n\tradialSegments = Math.floor( radialSegments ) || 8;\n\tp = p || 2;\n\tq = q || 3;\n\n\t// buffers\n\n\tvar indices = [];\n\tvar vertices = [];\n\tvar normals = [];\n\tvar uvs = [];\n\n\t// helper variables\n\n\tvar i, j;\n\n\tvar vertex = new Vector3();\n\tvar normal = new Vector3();\n\tvar uv = new Vector2();\n\n\tvar P1 = new Vector3();\n\tvar P2 = new Vector3();\n\n\tvar B = new Vector3();\n\tvar T = new Vector3();\n\tvar N = new Vector3();\n\n\t// generate vertices, normals and uvs\n\n\tfor ( i = 0; i <= tubularSegments; ++ i ) {\n\n\t\t// the radian \"u\" is used to calculate the position on the torus curve of the current tubular segement\n\n\t\tvar u = i / tubularSegments * p * Math.PI * 2;\n\n\t\t// now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.\n\t\t// these points are used to create a special \"coordinate space\", which is necessary to calculate the correct vertex positions\n\n\t\tcalculatePositionOnCurve( u, p, q, radius, P1 );\n\t\tcalculatePositionOnCurve( u + 0.01, p, q, radius, P2 );\n\n\t\t// calculate orthonormal basis\n\n\t\tT.subVectors( P2, P1 );\n\t\tN.addVectors( P2, P1 );\n\t\tB.crossVectors( T, N );\n\t\tN.crossVectors( B, T );\n\n\t\t// normalize B, N. T can be ignored, we don't use it\n\n\t\tB.normalize();\n\t\tN.normalize();\n\n\t\tfor ( j = 0; j <= radialSegments; ++ j ) {\n\n\t\t\t// now calculate the vertices. they are nothing more than an extrusion of the torus curve.\n\t\t\t// because we extrude a shape in the xy-plane, there is no need to calculate a z-value.\n\n\t\t\tvar v = j / radialSegments * Math.PI * 2;\n\t\t\tvar cx = - tube * Math.cos( v );\n\t\t\tvar cy = tube * Math.sin( v );\n\n\t\t\t// now calculate the final vertex position.\n\t\t\t// first we orient the extrusion with our basis vectos, then we add it to the current position on the curve\n\n\t\t\tvertex.x = P1.x + ( cx * N.x + cy * B.x );\n\t\t\tvertex.y = P1.y + ( cx * N.y + cy * B.y );\n\t\t\tvertex.z = P1.z + ( cx * N.z + cy * B.z );\n\n\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t// normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)\n\n\t\t\tnormal.subVectors( vertex, P1 ).normalize();\n\n\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t// uv\n\n\t\t\tuvs.push( i / tubularSegments );\n\t\t\tuvs.push( j / radialSegments );\n\n\t\t}\n\n\t}\n\n\t// generate indices\n\n\tfor ( j = 1; j <= tubularSegments; j ++ ) {\n\n\t\tfor ( i = 1; i <= radialSegments; i ++ ) {\n\n\t\t\t// indices\n\n\t\t\tvar a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );\n\t\t\tvar b = ( radialSegments + 1 ) * j + ( i - 1 );\n\t\t\tvar c = ( radialSegments + 1 ) * j + i;\n\t\t\tvar d = ( radialSegments + 1 ) * ( j - 1 ) + i;\n\n\t\t\t// faces\n\n\t\t\tindices.push( a, b, d );\n\t\t\tindices.push( b, c, d );\n\n\t\t}\n\n\t}\n\n\t// build geometry\n\n\tthis.setIndex( indices );\n\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t// this function calculates the current position on the torus curve\n\n\tfunction calculatePositionOnCurve( u, p, q, radius, position ) {\n\n\t\tvar cu = Math.cos( u );\n\t\tvar su = Math.sin( u );\n\t\tvar quOverP = q / p * u;\n\t\tvar cs = Math.cos( quOverP );\n\n\t\tposition.x = radius * ( 2 + cs ) * 0.5 * cu;\n\t\tposition.y = radius * ( 2 + cs ) * su * 0.5;\n\t\tposition.z = radius * Math.sin( quOverP ) * 0.5;\n\n\t}\n\n}\n\nTorusKnotBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\nTorusKnotBufferGeometry.prototype.constructor = TorusKnotBufferGeometry;\n\n/**\n * @author oosmoxiecode\n * @author mrdoob / http://mrdoob.com/\n * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3DLite/src/away3dlite/primitives/Torus.as?r=2888\n */\n\nfunction TorusGeometry( radius, tube, radialSegments, tubularSegments, arc ) {\n\n\tGeometry.call( this );\n\n\tthis.type = 'TorusGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\ttube: tube,\n\t\tradialSegments: radialSegments,\n\t\ttubularSegments: tubularSegments,\n\t\tarc: arc\n\t};\n\n\tthis.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) );\n\n}\n\nTorusGeometry.prototype = Object.create( Geometry.prototype );\nTorusGeometry.prototype.constructor = TorusGeometry;\n\n/**\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) {\n\n\tBufferGeometry.call( this );\n\n\tthis.type = 'TorusBufferGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\ttube: tube,\n\t\tradialSegments: radialSegments,\n\t\ttubularSegments: tubularSegments,\n\t\tarc: arc\n\t};\n\n\tradius = radius || 100;\n\ttube = tube || 40;\n\tradialSegments = Math.floor( radialSegments ) || 8;\n\ttubularSegments = Math.floor( tubularSegments ) || 6;\n\tarc = arc || Math.PI * 2;\n\n\t// buffers\n\n\tvar indices = [];\n\tvar vertices = [];\n\tvar normals = [];\n\tvar uvs = [];\n\n\t// helper variables\n\n\tvar center = new Vector3();\n\tvar vertex = new Vector3();\n\tvar normal = new Vector3();\n\n\tvar j, i;\n\n\t// generate vertices, normals and uvs\n\n\tfor ( j = 0; j <= radialSegments; j ++ ) {\n\n\t\tfor ( i = 0; i <= tubularSegments; i ++ ) {\n\n\t\t\tvar u = i / tubularSegments * arc;\n\t\t\tvar v = j / radialSegments * Math.PI * 2;\n\n\t\t\t// vertex\n\n\t\t\tvertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );\n\t\t\tvertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );\n\t\t\tvertex.z = tube * Math.sin( v );\n\n\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t// normal\n\n\t\t\tcenter.x = radius * Math.cos( u );\n\t\t\tcenter.y = radius * Math.sin( u );\n\t\t\tnormal.subVectors( vertex, center ).normalize();\n\n\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t// uv\n\n\t\t\tuvs.push( i / tubularSegments );\n\t\t\tuvs.push( j / radialSegments );\n\n\t\t}\n\n\t}\n\n\t// generate indices\n\n\tfor ( j = 1; j <= radialSegments; j ++ ) {\n\n\t\tfor ( i = 1; i <= tubularSegments; i ++ ) {\n\n\t\t\t// indices\n\n\t\t\tvar a = ( tubularSegments + 1 ) * j + i - 1;\n\t\t\tvar b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;\n\t\t\tvar c = ( tubularSegments + 1 ) * ( j - 1 ) + i;\n\t\t\tvar d = ( tubularSegments + 1 ) * j + i;\n\n\t\t\t// faces\n\n\t\t\tindices.push( a, b, d );\n\t\t\tindices.push( b, c, d );\n\n\t\t}\n\n\t}\n\n\t// build geometry\n\n\tthis.setIndex( indices );\n\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n}\n\nTorusBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\nTorusBufferGeometry.prototype.constructor = TorusBufferGeometry;\n\n/**\n * @author zz85 / http://www.lab4games.net/zz85/blog\n */\n\nvar ShapeUtils = {\n\n\t// calculate area of the contour polygon\n\n\tarea: function ( contour ) {\n\n\t\tvar n = contour.length;\n\t\tvar a = 0.0;\n\n\t\tfor ( var p = n - 1, q = 0; q < n; p = q ++ ) {\n\n\t\t\ta += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;\n\n\t\t}\n\n\t\treturn a * 0.5;\n\n\t},\n\n\ttriangulate: ( function () {\n\n\t\t/**\n\t\t * This code is a quick port of code written in C++ which was submitted to\n\t\t * flipcode.com by John W. Ratcliff // July 22, 2000\n\t\t * See original code and more information here:\n\t\t * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml\n\t\t *\n\t\t * ported to actionscript by Zevan Rosser\n\t\t * www.actionsnippet.com\n\t\t *\n\t\t * ported to javascript by Joshua Koo\n\t\t * http://www.lab4games.net/zz85/blog\n\t\t *\n\t\t */\n\n\t\tfunction snip( contour, u, v, w, n, verts ) {\n\n\t\t\tvar p;\n\t\t\tvar ax, ay, bx, by;\n\t\t\tvar cx, cy, px, py;\n\n\t\t\tax = contour[ verts[ u ] ].x;\n\t\t\tay = contour[ verts[ u ] ].y;\n\n\t\t\tbx = contour[ verts[ v ] ].x;\n\t\t\tby = contour[ verts[ v ] ].y;\n\n\t\t\tcx = contour[ verts[ w ] ].x;\n\t\t\tcy = contour[ verts[ w ] ].y;\n\n\t\t\tif ( ( bx - ax ) * ( cy - ay ) - ( by - ay ) * ( cx - ax ) <= 0 ) return false;\n\n\t\t\tvar aX, aY, bX, bY, cX, cY;\n\t\t\tvar apx, apy, bpx, bpy, cpx, cpy;\n\t\t\tvar cCROSSap, bCROSScp, aCROSSbp;\n\n\t\t\taX = cx - bx; aY = cy - by;\n\t\t\tbX = ax - cx; bY = ay - cy;\n\t\t\tcX = bx - ax; cY = by - ay;\n\n\t\t\tfor ( p = 0; p < n; p ++ ) {\n\n\t\t\t\tpx = contour[ verts[ p ] ].x;\n\t\t\t\tpy = contour[ verts[ p ] ].y;\n\n\t\t\t\tif ( ( ( px === ax ) && ( py === ay ) ) ||\n\t\t\t\t\t ( ( px === bx ) && ( py === by ) ) ||\n\t\t\t\t\t ( ( px === cx ) && ( py === cy ) ) )\tcontinue;\n\n\t\t\t\tapx = px - ax; apy = py - ay;\n\t\t\t\tbpx = px - bx; bpy = py - by;\n\t\t\t\tcpx = px - cx; cpy = py - cy;\n\n\t\t\t\t// see if p is inside triangle abc\n\n\t\t\t\taCROSSbp = aX * bpy - aY * bpx;\n\t\t\t\tcCROSSap = cX * apy - cY * apx;\n\t\t\t\tbCROSScp = bX * cpy - bY * cpx;\n\n\t\t\t\tif ( ( aCROSSbp >= - Number.EPSILON ) && ( bCROSScp >= - Number.EPSILON ) && ( cCROSSap >= - Number.EPSILON ) ) return false;\n\n\t\t\t}\n\n\t\t\treturn true;\n\n\t\t}\n\n\t\t// takes in an contour array and returns\n\n\t\treturn function triangulate( contour, indices ) {\n\n\t\t\tvar n = contour.length;\n\n\t\t\tif ( n < 3 ) return null;\n\n\t\t\tvar result = [],\n\t\t\t\tverts = [],\n\t\t\t\tvertIndices = [];\n\n\t\t\t/* we want a counter-clockwise polygon in verts */\n\n\t\t\tvar u, v, w;\n\n\t\t\tif ( ShapeUtils.area( contour ) > 0.0 ) {\n\n\t\t\t\tfor ( v = 0; v < n; v ++ ) verts[ v ] = v;\n\n\t\t\t} else {\n\n\t\t\t\tfor ( v = 0; v < n; v ++ ) verts[ v ] = ( n - 1 ) - v;\n\n\t\t\t}\n\n\t\t\tvar nv = n;\n\n\t\t\t/* remove nv - 2 vertices, creating 1 triangle every time */\n\n\t\t\tvar count = 2 * nv; /* error detection */\n\n\t\t\tfor ( v = nv - 1; nv > 2; ) {\n\n\t\t\t\t/* if we loop, it is probably a non-simple polygon */\n\n\t\t\t\tif ( ( count -- ) <= 0 ) {\n\n\t\t\t\t\t//** Triangulate: ERROR - probable bad polygon!\n\n\t\t\t\t\t//throw ( \"Warning, unable to triangulate polygon!\" );\n\t\t\t\t\t//return null;\n\t\t\t\t\t// Sometimes warning is fine, especially polygons are triangulated in reverse.\n\t\t\t\t\tconsole.warn( 'THREE.ShapeUtils: Unable to triangulate polygon! in triangulate()' );\n\n\t\t\t\t\tif ( indices ) return vertIndices;\n\t\t\t\t\treturn result;\n\n\t\t\t\t}\n\n\t\t\t\t/* three consecutive vertices in current polygon, */\n\n\t\t\t\tu = v; \t \tif ( nv <= u ) u = 0; /* previous */\n\t\t\t\tv = u + 1; if ( nv <= v ) v = 0; /* new v */\n\t\t\t\tw = v + 1; if ( nv <= w ) w = 0; /* next */\n\n\t\t\t\tif ( snip( contour, u, v, w, nv, verts ) ) {\n\n\t\t\t\t\tvar a, b, c, s, t;\n\n\t\t\t\t\t/* true names of the vertices */\n\n\t\t\t\t\ta = verts[ u ];\n\t\t\t\t\tb = verts[ v ];\n\t\t\t\t\tc = verts[ w ];\n\n\t\t\t\t\t/* output Triangle */\n\n\t\t\t\t\tresult.push( [ contour[ a ],\n\t\t\t\t\t\tcontour[ b ],\n\t\t\t\t\t\tcontour[ c ] ] );\n\n\n\t\t\t\t\tvertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] );\n\n\t\t\t\t\t/* remove v from the remaining polygon */\n\n\t\t\t\t\tfor ( s = v, t = v + 1; t < nv; s ++, t ++ ) {\n\n\t\t\t\t\t\tverts[ s ] = verts[ t ];\n\n\t\t\t\t\t}\n\n\t\t\t\t\tnv --;\n\n\t\t\t\t\t/* reset error detection counter */\n\n\t\t\t\t\tcount = 2 * nv;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( indices ) return vertIndices;\n\t\t\treturn result;\n\n\t\t}\n\n\t} )(),\n\n\ttriangulateShape: function ( contour, holes ) {\n\n\t\tfunction removeDupEndPts(points) {\n\n\t\t\tvar l = points.length;\n\n\t\t\tif ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {\n\n\t\t\t\tpoints.pop();\n\n\t\t\t}\n\n\t\t}\n\n\t\tremoveDupEndPts( contour );\n\t\tholes.forEach( removeDupEndPts );\n\n\t\tfunction point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) {\n\n\t\t\t// inOtherPt needs to be collinear to the inSegment\n\t\t\tif ( inSegPt1.x !== inSegPt2.x ) {\n\n\t\t\t\tif ( inSegPt1.x < inSegPt2.x ) {\n\n\t\t\t\t\treturn\t( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) );\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn\t( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tif ( inSegPt1.y < inSegPt2.y ) {\n\n\t\t\t\t\treturn\t( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) );\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn\t( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) {\n\n\t\t\tvar seg1dx = inSeg1Pt2.x - inSeg1Pt1.x, seg1dy = inSeg1Pt2.y - inSeg1Pt1.y;\n\t\t\tvar seg2dx = inSeg2Pt2.x - inSeg2Pt1.x, seg2dy = inSeg2Pt2.y - inSeg2Pt1.y;\n\n\t\t\tvar seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x;\n\t\t\tvar seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y;\n\n\t\t\tvar limit\t\t= seg1dy * seg2dx - seg1dx * seg2dy;\n\t\t\tvar perpSeg1\t= seg1dy * seg1seg2dx - seg1dx * seg1seg2dy;\n\n\t\t\tif ( Math.abs( limit ) > Number.EPSILON ) {\n\n\t\t\t\t// not parallel\n\n\t\t\t\tvar perpSeg2;\n\t\t\t\tif ( limit > 0 ) {\n\n\t\t\t\t\tif ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) \t\treturn [];\n\t\t\t\t\tperpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;\n\t\t\t\t\tif ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) \t\treturn [];\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) \t\treturn [];\n\t\t\t\t\tperpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;\n\t\t\t\t\tif ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) \t\treturn [];\n\n\t\t\t\t}\n\n\t\t\t\t// i.e. to reduce rounding errors\n\t\t\t\t// intersection at endpoint of segment#1?\n\t\t\t\tif ( perpSeg2 === 0 ) {\n\n\t\t\t\t\tif ( ( inExcludeAdjacentSegs ) &&\n\t\t\t\t\t\t ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) )\t\treturn [];\n\t\t\t\t\treturn [ inSeg1Pt1 ];\n\n\t\t\t\t}\n\t\t\t\tif ( perpSeg2 === limit ) {\n\n\t\t\t\t\tif ( ( inExcludeAdjacentSegs ) &&\n\t\t\t\t\t\t ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) )\t\treturn [];\n\t\t\t\t\treturn [ inSeg1Pt2 ];\n\n\t\t\t\t}\n\t\t\t\t// intersection at endpoint of segment#2?\n\t\t\t\tif ( perpSeg1 === 0 )\t\treturn [ inSeg2Pt1 ];\n\t\t\t\tif ( perpSeg1 === limit )\treturn [ inSeg2Pt2 ];\n\n\t\t\t\t// return real intersection point\n\t\t\t\tvar factorSeg1 = perpSeg2 / limit;\n\t\t\t\treturn\t[ { x: inSeg1Pt1.x + factorSeg1 * seg1dx,\n\t\t\t\t\t\t\ty: inSeg1Pt1.y + factorSeg1 * seg1dy } ];\n\n\t\t\t} else {\n\n\t\t\t\t// parallel or collinear\n\t\t\t\tif ( ( perpSeg1 !== 0 ) ||\n\t\t\t\t\t ( seg2dy * seg1seg2dx !== seg2dx * seg1seg2dy ) ) \t\t\treturn [];\n\n\t\t\t\t// they are collinear or degenerate\n\t\t\t\tvar seg1Pt = ( ( seg1dx === 0 ) && ( seg1dy === 0 ) );\t// segment1 is just a point?\n\t\t\t\tvar seg2Pt = ( ( seg2dx === 0 ) && ( seg2dy === 0 ) );\t// segment2 is just a point?\n\t\t\t\t// both segments are points\n\t\t\t\tif ( seg1Pt && seg2Pt ) {\n\n\t\t\t\t\tif ( ( inSeg1Pt1.x !== inSeg2Pt1.x ) ||\n\t\t\t\t\t\t ( inSeg1Pt1.y !== inSeg2Pt1.y ) )\t\treturn [];\t// they are distinct points\n\t\t\t\t\treturn [ inSeg1Pt1 ]; \t\t\t\t\t\t// they are the same point\n\n\t\t\t\t}\n\t\t\t\t// segment#1 is a single point\n\t\t\t\tif ( seg1Pt ) {\n\n\t\t\t\t\tif ( ! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) )\t\treturn [];\t\t// but not in segment#2\n\t\t\t\t\treturn [ inSeg1Pt1 ];\n\n\t\t\t\t}\n\t\t\t\t// segment#2 is a single point\n\t\t\t\tif ( seg2Pt ) {\n\n\t\t\t\t\tif ( ! point_in_segment_2D_colin( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1 ) )\t\treturn [];\t\t// but not in segment#1\n\t\t\t\t\treturn [ inSeg2Pt1 ];\n\n\t\t\t\t}\n\n\t\t\t\t// they are collinear segments, which might overlap\n\t\t\t\tvar seg1min, seg1max, seg1minVal, seg1maxVal;\n\t\t\t\tvar seg2min, seg2max, seg2minVal, seg2maxVal;\n\t\t\t\tif ( seg1dx !== 0 ) {\n\n\t\t\t\t\t// the segments are NOT on a vertical line\n\t\t\t\t\tif ( inSeg1Pt1.x < inSeg1Pt2.x ) {\n\n\t\t\t\t\t\tseg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x;\n\t\t\t\t\t\tseg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tseg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x;\n\t\t\t\t\t\tseg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x;\n\n\t\t\t\t\t}\n\t\t\t\t\tif ( inSeg2Pt1.x < inSeg2Pt2.x ) {\n\n\t\t\t\t\t\tseg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x;\n\t\t\t\t\t\tseg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tseg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x;\n\t\t\t\t\t\tseg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x;\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// the segments are on a vertical line\n\t\t\t\t\tif ( inSeg1Pt1.y < inSeg1Pt2.y ) {\n\n\t\t\t\t\t\tseg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y;\n\t\t\t\t\t\tseg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tseg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y;\n\t\t\t\t\t\tseg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y;\n\n\t\t\t\t\t}\n\t\t\t\t\tif ( inSeg2Pt1.y < inSeg2Pt2.y ) {\n\n\t\t\t\t\t\tseg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y;\n\t\t\t\t\t\tseg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tseg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y;\n\t\t\t\t\t\tseg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t\tif ( seg1minVal <= seg2minVal ) {\n\n\t\t\t\t\tif ( seg1maxVal < seg2minVal )\treturn [];\n\t\t\t\t\tif ( seg1maxVal === seg2minVal )\t{\n\n\t\t\t\t\t\tif ( inExcludeAdjacentSegs )\t\treturn [];\n\t\t\t\t\t\treturn [ seg2min ];\n\n\t\t\t\t\t}\n\t\t\t\t\tif ( seg1maxVal <= seg2maxVal )\treturn [ seg2min, seg1max ];\n\t\t\t\t\treturn\t[ seg2min, seg2max ];\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( seg1minVal > seg2maxVal )\treturn [];\n\t\t\t\t\tif ( seg1minVal === seg2maxVal )\t{\n\n\t\t\t\t\t\tif ( inExcludeAdjacentSegs )\t\treturn [];\n\t\t\t\t\t\treturn [ seg1min ];\n\n\t\t\t\t\t}\n\t\t\t\t\tif ( seg1maxVal <= seg2maxVal )\treturn [ seg1min, seg1max ];\n\t\t\t\t\treturn\t[ seg1min, seg2max ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) {\n\n\t\t\t// The order of legs is important\n\n\t\t\t// translation of all points, so that Vertex is at (0,0)\n\t\t\tvar legFromPtX\t= inLegFromPt.x - inVertex.x, legFromPtY\t= inLegFromPt.y - inVertex.y;\n\t\t\tvar legToPtX\t= inLegToPt.x\t- inVertex.x, legToPtY\t\t= inLegToPt.y\t- inVertex.y;\n\t\t\tvar otherPtX\t= inOtherPt.x\t- inVertex.x, otherPtY\t\t= inOtherPt.y\t- inVertex.y;\n\n\t\t\t// main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg.\n\t\t\tvar from2toAngle\t= legFromPtX * legToPtY - legFromPtY * legToPtX;\n\t\t\tvar from2otherAngle\t= legFromPtX * otherPtY - legFromPtY * otherPtX;\n\n\t\t\tif ( Math.abs( from2toAngle ) > Number.EPSILON ) {\n\n\t\t\t\t// angle != 180 deg.\n\n\t\t\t\tvar other2toAngle\t\t= otherPtX * legToPtY - otherPtY * legToPtX;\n\t\t\t\t// console.log( \"from2to: \" + from2toAngle + \", from2other: \" + from2otherAngle + \", other2to: \" + other2toAngle );\n\n\t\t\t\tif ( from2toAngle > 0 ) {\n\n\t\t\t\t\t// main angle < 180 deg.\n\t\t\t\t\treturn\t( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// main angle > 180 deg.\n\t\t\t\t\treturn\t( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// angle == 180 deg.\n\t\t\t\t// console.log( \"from2to: 180 deg., from2other: \" + from2otherAngle );\n\t\t\t\treturn\t( from2otherAngle > 0 );\n\n\t\t\t}\n\n\t\t}\n\n\n\t\tfunction removeHoles( contour, holes ) {\n\n\t\t\tvar shape = contour.concat(); // work on this shape\n\t\t\tvar hole;\n\n\t\t\tfunction isCutLineInsideAngles( inShapeIdx, inHoleIdx ) {\n\n\t\t\t\t// Check if hole point lies within angle around shape point\n\t\t\t\tvar lastShapeIdx = shape.length - 1;\n\n\t\t\t\tvar prevShapeIdx = inShapeIdx - 1;\n\t\t\t\tif ( prevShapeIdx < 0 )\t\t\tprevShapeIdx = lastShapeIdx;\n\n\t\t\t\tvar nextShapeIdx = inShapeIdx + 1;\n\t\t\t\tif ( nextShapeIdx > lastShapeIdx )\tnextShapeIdx = 0;\n\n\t\t\t\tvar insideAngle = isPointInsideAngle( shape[ inShapeIdx ], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[ inHoleIdx ] );\n\t\t\t\tif ( ! insideAngle ) {\n\n\t\t\t\t\t// console.log( \"Vertex (Shape): \" + inShapeIdx + \", Point: \" + hole[inHoleIdx].x + \"/\" + hole[inHoleIdx].y );\n\t\t\t\t\treturn\tfalse;\n\n\t\t\t\t}\n\n\t\t\t\t// Check if shape point lies within angle around hole point\n\t\t\t\tvar lastHoleIdx = hole.length - 1;\n\n\t\t\t\tvar prevHoleIdx = inHoleIdx - 1;\n\t\t\t\tif ( prevHoleIdx < 0 )\t\t\tprevHoleIdx = lastHoleIdx;\n\n\t\t\t\tvar nextHoleIdx = inHoleIdx + 1;\n\t\t\t\tif ( nextHoleIdx > lastHoleIdx )\tnextHoleIdx = 0;\n\n\t\t\t\tinsideAngle = isPointInsideAngle( hole[ inHoleIdx ], hole[ prevHoleIdx ], hole[ nextHoleIdx ], shape[ inShapeIdx ] );\n\t\t\t\tif ( ! insideAngle ) {\n\n\t\t\t\t\t// console.log( \"Vertex (Hole): \" + inHoleIdx + \", Point: \" + shape[inShapeIdx].x + \"/\" + shape[inShapeIdx].y );\n\t\t\t\t\treturn\tfalse;\n\n\t\t\t\t}\n\n\t\t\t\treturn\ttrue;\n\n\t\t\t}\n\n\t\t\tfunction intersectsShapeEdge( inShapePt, inHolePt ) {\n\n\t\t\t\t// checks for intersections with shape edges\n\t\t\t\tvar sIdx, nextIdx, intersection;\n\t\t\t\tfor ( sIdx = 0; sIdx < shape.length; sIdx ++ ) {\n\n\t\t\t\t\tnextIdx = sIdx + 1; nextIdx %= shape.length;\n\t\t\t\t\tintersection = intersect_segments_2D( inShapePt, inHolePt, shape[ sIdx ], shape[ nextIdx ], true );\n\t\t\t\t\tif ( intersection.length > 0 )\t\treturn\ttrue;\n\n\t\t\t\t}\n\n\t\t\t\treturn\tfalse;\n\n\t\t\t}\n\n\t\t\tvar indepHoles = [];\n\n\t\t\tfunction intersectsHoleEdge( inShapePt, inHolePt ) {\n\n\t\t\t\t// checks for intersections with hole edges\n\t\t\t\tvar ihIdx, chkHole,\n\t\t\t\t\thIdx, nextIdx, intersection;\n\t\t\t\tfor ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx ++ ) {\n\n\t\t\t\t\tchkHole = holes[ indepHoles[ ihIdx ]];\n\t\t\t\t\tfor ( hIdx = 0; hIdx < chkHole.length; hIdx ++ ) {\n\n\t\t\t\t\t\tnextIdx = hIdx + 1; nextIdx %= chkHole.length;\n\t\t\t\t\t\tintersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[ hIdx ], chkHole[ nextIdx ], true );\n\t\t\t\t\t\tif ( intersection.length > 0 )\t\treturn\ttrue;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t\treturn\tfalse;\n\n\t\t\t}\n\n\t\t\tvar holeIndex, shapeIndex,\n\t\t\t\tshapePt, holePt,\n\t\t\t\tholeIdx, cutKey, failedCuts = [],\n\t\t\t\ttmpShape1, tmpShape2,\n\t\t\t\ttmpHole1, tmpHole2;\n\n\t\t\tfor ( var h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\tindepHoles.push( h );\n\n\t\t\t}\n\n\t\t\tvar minShapeIndex = 0;\n\t\t\tvar counter = indepHoles.length * 2;\n\t\t\twhile ( indepHoles.length > 0 ) {\n\n\t\t\t\tcounter --;\n\t\t\t\tif ( counter < 0 ) {\n\n\t\t\t\t\tconsole.log( \"Infinite Loop! Holes left:\" + indepHoles.length + \", Probably Hole outside Shape!\" );\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t\t// search for shape-vertex and hole-vertex,\n\t\t\t\t// which can be connected without intersections\n\t\t\t\tfor ( shapeIndex = minShapeIndex; shapeIndex < shape.length; shapeIndex ++ ) {\n\n\t\t\t\t\tshapePt = shape[ shapeIndex ];\n\t\t\t\t\tholeIndex\t= - 1;\n\n\t\t\t\t\t// search for hole which can be reached without intersections\n\t\t\t\t\tfor ( var h = 0; h < indepHoles.length; h ++ ) {\n\n\t\t\t\t\t\tholeIdx = indepHoles[ h ];\n\n\t\t\t\t\t\t// prevent multiple checks\n\t\t\t\t\t\tcutKey = shapePt.x + \":\" + shapePt.y + \":\" + holeIdx;\n\t\t\t\t\t\tif ( failedCuts[ cutKey ] !== undefined )\t\t\tcontinue;\n\n\t\t\t\t\t\thole = holes[ holeIdx ];\n\t\t\t\t\t\tfor ( var h2 = 0; h2 < hole.length; h2 ++ ) {\n\n\t\t\t\t\t\t\tholePt = hole[ h2 ];\n\t\t\t\t\t\t\tif ( ! isCutLineInsideAngles( shapeIndex, h2 ) )\t\tcontinue;\n\t\t\t\t\t\t\tif ( intersectsShapeEdge( shapePt, holePt ) )\t\tcontinue;\n\t\t\t\t\t\t\tif ( intersectsHoleEdge( shapePt, holePt ) )\t\tcontinue;\n\n\t\t\t\t\t\t\tholeIndex = h2;\n\t\t\t\t\t\t\tindepHoles.splice( h, 1 );\n\n\t\t\t\t\t\t\ttmpShape1 = shape.slice( 0, shapeIndex + 1 );\n\t\t\t\t\t\t\ttmpShape2 = shape.slice( shapeIndex );\n\t\t\t\t\t\t\ttmpHole1 = hole.slice( holeIndex );\n\t\t\t\t\t\t\ttmpHole2 = hole.slice( 0, holeIndex + 1 );\n\n\t\t\t\t\t\t\tshape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 );\n\n\t\t\t\t\t\t\tminShapeIndex = shapeIndex;\n\n\t\t\t\t\t\t\t// Debug only, to show the selected cuts\n\t\t\t\t\t\t\t// glob_CutLines.push( [ shapePt, holePt ] );\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( holeIndex >= 0 )\tbreak;\t\t// hole-vertex found\n\n\t\t\t\t\t\tfailedCuts[ cutKey ] = true;\t\t\t// remember failure\n\n\t\t\t\t\t}\n\t\t\t\t\tif ( holeIndex >= 0 )\tbreak;\t\t// hole-vertex found\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn shape; \t\t\t/* shape with no holes */\n\n\t\t}\n\n\n\t\tvar i, il, f, face,\n\t\t\tkey, index,\n\t\t\tallPointsMap = {};\n\n\t\t// To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first.\n\n\t\tvar allpoints = contour.concat();\n\n\t\tfor ( var h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\tArray.prototype.push.apply( allpoints, holes[ h ] );\n\n\t\t}\n\n\t\t//console.log( \"allpoints\",allpoints, allpoints.length );\n\n\t\t// prepare all points map\n\n\t\tfor ( i = 0, il = allpoints.length; i < il; i ++ ) {\n\n\t\t\tkey = allpoints[ i ].x + \":\" + allpoints[ i ].y;\n\n\t\t\tif ( allPointsMap[ key ] !== undefined ) {\n\n\t\t\t\tconsole.warn( \"THREE.ShapeUtils: Duplicate point\", key, i );\n\n\t\t\t}\n\n\t\t\tallPointsMap[ key ] = i;\n\n\t\t}\n\n\t\t// remove holes by cutting paths to holes and adding them to the shape\n\t\tvar shapeWithoutHoles = removeHoles( contour, holes );\n\n\t\tvar triangles = ShapeUtils.triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape\n\t\t//console.log( \"triangles\",triangles, triangles.length );\n\n\t\t// check all face vertices against all points map\n\n\t\tfor ( i = 0, il = triangles.length; i < il; i ++ ) {\n\n\t\t\tface = triangles[ i ];\n\n\t\t\tfor ( f = 0; f < 3; f ++ ) {\n\n\t\t\t\tkey = face[ f ].x + \":\" + face[ f ].y;\n\n\t\t\t\tindex = allPointsMap[ key ];\n\n\t\t\t\tif ( index !== undefined ) {\n\n\t\t\t\t\tface[ f ] = index;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn triangles.concat();\n\n\t},\n\n\tisClockWise: function ( pts ) {\n\n\t\treturn ShapeUtils.area( pts ) < 0;\n\n\t}\n\n};\n\n/**\n * @author zz85 / http://www.lab4games.net/zz85/blog\n *\n * Creates extruded geometry from a path shape.\n *\n * parameters = {\n *\n * curveSegments: , // number of points on the curves\n * steps: , // number of points for z-side extrusions / used for subdividing segments of extrude spline too\n * amount: , // Depth to extrude the shape\n *\n * bevelEnabled: , // turn on bevel\n * bevelThickness: , // how deep into the original shape bevel goes\n * bevelSize: , // how far from shape outline is bevel\n * bevelSegments: , // number of bevel layers\n *\n * extrudePath: // curve to extrude shape along\n * frames: // containing arrays of tangents, normals, binormals\n *\n * uvGenerator: // object that provides UV generator functions\n *\n * }\n **/\n\nfunction ExtrudeGeometry( shapes, options ) {\n\n\tif ( typeof( shapes ) === \"undefined\" ) {\n\n\t\tshapes = [];\n\t\treturn;\n\n\t}\n\n\tGeometry.call( this );\n\n\tthis.type = 'ExtrudeGeometry';\n\n\tshapes = Array.isArray( shapes ) ? shapes : [ shapes ];\n\n\tthis.addShapeList( shapes, options );\n\n\tthis.computeFaceNormals();\n\n\t// can't really use automatic vertex normals\n\t// as then front and back sides get smoothed too\n\t// should do separate smoothing just for sides\n\n\t//this.computeVertexNormals();\n\n\t//console.log( \"took\", ( Date.now() - startTime ) );\n\n}\n\nExtrudeGeometry.prototype = Object.create( Geometry.prototype );\nExtrudeGeometry.prototype.constructor = ExtrudeGeometry;\n\nExtrudeGeometry.prototype.addShapeList = function ( shapes, options ) {\n\n\tvar sl = shapes.length;\n\n\tfor ( var s = 0; s < sl; s ++ ) {\n\n\t\tvar shape = shapes[ s ];\n\t\tthis.addShape( shape, options );\n\n\t}\n\n};\n\nExtrudeGeometry.prototype.addShape = function ( shape, options ) {\n\n\tvar amount = options.amount !== undefined ? options.amount : 100;\n\n\tvar bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10\n\tvar bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8\n\tvar bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;\n\n\tvar bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false\n\n\tvar curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;\n\n\tvar steps = options.steps !== undefined ? options.steps : 1;\n\n\tvar extrudePath = options.extrudePath;\n\tvar extrudePts, extrudeByPath = false;\n\n\t// Use default WorldUVGenerator if no UV generators are specified.\n\tvar uvgen = options.UVGenerator !== undefined ? options.UVGenerator : ExtrudeGeometry.WorldUVGenerator;\n\n\tvar splineTube, binormal, normal, position2;\n\tif ( extrudePath ) {\n\n\t\textrudePts = extrudePath.getSpacedPoints( steps );\n\n\t\textrudeByPath = true;\n\t\tbevelEnabled = false; // bevels not supported for path extrusion\n\n\t\t// SETUP TNB variables\n\n\t\t// TODO1 - have a .isClosed in spline?\n\n\t\tsplineTube = options.frames !== undefined ? options.frames : extrudePath.computeFrenetFrames( steps, false );\n\n\t\t// console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);\n\n\t\tbinormal = new Vector3();\n\t\tnormal = new Vector3();\n\t\tposition2 = new Vector3();\n\n\t}\n\n\t// Safeguards if bevels are not enabled\n\n\tif ( ! bevelEnabled ) {\n\n\t\tbevelSegments = 0;\n\t\tbevelThickness = 0;\n\t\tbevelSize = 0;\n\n\t}\n\n\t// Variables initialization\n\n\tvar ahole, h, hl; // looping of holes\n\tvar scope = this;\n\n\tvar shapesOffset = this.vertices.length;\n\n\tvar shapePoints = shape.extractPoints( curveSegments );\n\n\tvar vertices = shapePoints.shape;\n\tvar holes = shapePoints.holes;\n\n\tvar reverse = ! ShapeUtils.isClockWise( vertices );\n\n\tif ( reverse ) {\n\n\t\tvertices = vertices.reverse();\n\n\t\t// Maybe we should also check if holes are in the opposite direction, just to be safe ...\n\n\t\tfor ( h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\tahole = holes[ h ];\n\n\t\t\tif ( ShapeUtils.isClockWise( ahole ) ) {\n\n\t\t\t\tholes[ h ] = ahole.reverse();\n\n\t\t\t}\n\n\t\t}\n\n\t\treverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)!\n\n\t}\n\n\n\tvar faces = ShapeUtils.triangulateShape( vertices, holes );\n\n\t/* Vertices */\n\n\tvar contour = vertices; // vertices has all points but contour has only points of circumference\n\n\tfor ( h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\tahole = holes[ h ];\n\n\t\tvertices = vertices.concat( ahole );\n\n\t}\n\n\n\tfunction scalePt2( pt, vec, size ) {\n\n\t\tif ( ! vec ) console.error( \"THREE.ExtrudeGeometry: vec does not exist\" );\n\n\t\treturn vec.clone().multiplyScalar( size ).add( pt );\n\n\t}\n\n\tvar b, bs, t, z,\n\t\tvert, vlen = vertices.length,\n\t\tface, flen = faces.length;\n\n\n\t// Find directions for point movement\n\n\n\tfunction getBevelVec( inPt, inPrev, inNext ) {\n\n\t\t// computes for inPt the corresponding point inPt' on a new contour\n\t\t// shifted by 1 unit (length of normalized vector) to the left\n\t\t// if we walk along contour clockwise, this new contour is outside the old one\n\t\t//\n\t\t// inPt' is the intersection of the two lines parallel to the two\n\t\t// adjacent edges of inPt at a distance of 1 unit on the left side.\n\n\t\tvar v_trans_x, v_trans_y, shrink_by = 1;\t\t// resulting translation vector for inPt\n\n\t\t// good reading for geometry algorithms (here: line-line intersection)\n\t\t// http://geomalgorithms.com/a05-_intersect-1.html\n\n\t\tvar v_prev_x = inPt.x - inPrev.x, v_prev_y = inPt.y - inPrev.y;\n\t\tvar v_next_x = inNext.x - inPt.x, v_next_y = inNext.y - inPt.y;\n\n\t\tvar v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y );\n\n\t\t// check for collinear edges\n\t\tvar collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );\n\n\t\tif ( Math.abs( collinear0 ) > Number.EPSILON ) {\n\n\t\t\t// not collinear\n\n\t\t\t// length of vectors for normalizing\n\n\t\t\tvar v_prev_len = Math.sqrt( v_prev_lensq );\n\t\t\tvar v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );\n\n\t\t\t// shift adjacent points by unit vectors to the left\n\n\t\t\tvar ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );\n\t\t\tvar ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );\n\n\t\t\tvar ptNextShift_x = ( inNext.x - v_next_y / v_next_len );\n\t\t\tvar ptNextShift_y = ( inNext.y + v_next_x / v_next_len );\n\n\t\t\t// scaling factor for v_prev to intersection point\n\n\t\t\tvar sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y -\n\t\t\t\t\t\t( ptNextShift_y - ptPrevShift_y ) * v_next_x ) /\n\t\t\t\t\t ( v_prev_x * v_next_y - v_prev_y * v_next_x );\n\n\t\t\t// vector from inPt to intersection point\n\n\t\t\tv_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );\n\t\t\tv_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );\n\n\t\t\t// Don't normalize!, otherwise sharp corners become ugly\n\t\t\t// but prevent crazy spikes\n\t\t\tvar v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y );\n\t\t\tif ( v_trans_lensq <= 2 ) {\n\n\t\t\t\treturn\tnew Vector2( v_trans_x, v_trans_y );\n\n\t\t\t} else {\n\n\t\t\t\tshrink_by = Math.sqrt( v_trans_lensq / 2 );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// handle special case of collinear edges\n\n\t\t\tvar direction_eq = false;\t\t// assumes: opposite\n\t\t\tif ( v_prev_x > Number.EPSILON ) {\n\n\t\t\t\tif ( v_next_x > Number.EPSILON ) {\n\n\t\t\t\t\tdirection_eq = true;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tif ( v_prev_x < - Number.EPSILON ) {\n\n\t\t\t\t\tif ( v_next_x < - Number.EPSILON ) {\n\n\t\t\t\t\t\tdirection_eq = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) {\n\n\t\t\t\t\t\tdirection_eq = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( direction_eq ) {\n\n\t\t\t\t// console.log(\"Warning: lines are a straight sequence\");\n\t\t\t\tv_trans_x = - v_prev_y;\n\t\t\t\tv_trans_y = v_prev_x;\n\t\t\t\tshrink_by = Math.sqrt( v_prev_lensq );\n\n\t\t\t} else {\n\n\t\t\t\t// console.log(\"Warning: lines are a straight spike\");\n\t\t\t\tv_trans_x = v_prev_x;\n\t\t\t\tv_trans_y = v_prev_y;\n\t\t\t\tshrink_by = Math.sqrt( v_prev_lensq / 2 );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn\tnew Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by );\n\n\t}\n\n\n\tvar contourMovements = [];\n\n\tfor ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {\n\n\t\tif ( j === il ) j = 0;\n\t\tif ( k === il ) k = 0;\n\n\t\t// (j)---(i)---(k)\n\t\t// console.log('i,j,k', i, j , k)\n\n\t\tcontourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] );\n\n\t}\n\n\tvar holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat();\n\n\tfor ( h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\tahole = holes[ h ];\n\n\t\toneHoleMovements = [];\n\n\t\tfor ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {\n\n\t\t\tif ( j === il ) j = 0;\n\t\t\tif ( k === il ) k = 0;\n\n\t\t\t// (j)---(i)---(k)\n\t\t\toneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );\n\n\t\t}\n\n\t\tholesMovements.push( oneHoleMovements );\n\t\tverticesMovements = verticesMovements.concat( oneHoleMovements );\n\n\t}\n\n\n\t// Loop bevelSegments, 1 for the front, 1 for the back\n\n\tfor ( b = 0; b < bevelSegments; b ++ ) {\n\n\t\t//for ( b = bevelSegments; b > 0; b -- ) {\n\n\t\tt = b / bevelSegments;\n\t\tz = bevelThickness * Math.cos( t * Math.PI / 2 );\n\t\tbs = bevelSize * Math.sin( t * Math.PI / 2 );\n\n\t\t// contract shape\n\n\t\tfor ( i = 0, il = contour.length; i < il; i ++ ) {\n\n\t\t\tvert = scalePt2( contour[ i ], contourMovements[ i ], bs );\n\n\t\t\tv( vert.x, vert.y, - z );\n\n\t\t}\n\n\t\t// expand holes\n\n\t\tfor ( h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\tahole = holes[ h ];\n\t\t\toneHoleMovements = holesMovements[ h ];\n\n\t\t\tfor ( i = 0, il = ahole.length; i < il; i ++ ) {\n\n\t\t\t\tvert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );\n\n\t\t\t\tv( vert.x, vert.y, - z );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tbs = bevelSize;\n\n\t// Back facing vertices\n\n\tfor ( i = 0; i < vlen; i ++ ) {\n\n\t\tvert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];\n\n\t\tif ( ! extrudeByPath ) {\n\n\t\t\tv( vert.x, vert.y, 0 );\n\n\t\t} else {\n\n\t\t\t// v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );\n\n\t\t\tnormal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x );\n\t\t\tbinormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y );\n\n\t\t\tposition2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal );\n\n\t\t\tv( position2.x, position2.y, position2.z );\n\n\t\t}\n\n\t}\n\n\t// Add stepped vertices...\n\t// Including front facing vertices\n\n\tvar s;\n\n\tfor ( s = 1; s <= steps; s ++ ) {\n\n\t\tfor ( i = 0; i < vlen; i ++ ) {\n\n\t\t\tvert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];\n\n\t\t\tif ( ! extrudeByPath ) {\n\n\t\t\t\tv( vert.x, vert.y, amount / steps * s );\n\n\t\t\t} else {\n\n\t\t\t\t// v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );\n\n\t\t\t\tnormal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x );\n\t\t\t\tbinormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y );\n\n\t\t\t\tposition2.copy( extrudePts[ s ] ).add( normal ).add( binormal );\n\n\t\t\t\tv( position2.x, position2.y, position2.z );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\n\t// Add bevel segments planes\n\n\t//for ( b = 1; b <= bevelSegments; b ++ ) {\n\tfor ( b = bevelSegments - 1; b >= 0; b -- ) {\n\n\t\tt = b / bevelSegments;\n\t\tz = bevelThickness * Math.cos ( t * Math.PI / 2 );\n\t\tbs = bevelSize * Math.sin( t * Math.PI / 2 );\n\n\t\t// contract shape\n\n\t\tfor ( i = 0, il = contour.length; i < il; i ++ ) {\n\n\t\t\tvert = scalePt2( contour[ i ], contourMovements[ i ], bs );\n\t\t\tv( vert.x, vert.y, amount + z );\n\n\t\t}\n\n\t\t// expand holes\n\n\t\tfor ( h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\tahole = holes[ h ];\n\t\t\toneHoleMovements = holesMovements[ h ];\n\n\t\t\tfor ( i = 0, il = ahole.length; i < il; i ++ ) {\n\n\t\t\t\tvert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );\n\n\t\t\t\tif ( ! extrudeByPath ) {\n\n\t\t\t\t\tv( vert.x, vert.y, amount + z );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tv( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/* Faces */\n\n\t// Top and bottom faces\n\n\tbuildLidFaces();\n\n\t// Sides faces\n\n\tbuildSideFaces();\n\n\n\t///// Internal functions\n\n\tfunction buildLidFaces() {\n\n\t\tif ( bevelEnabled ) {\n\n\t\t\tvar layer = 0; // steps + 1\n\t\t\tvar offset = vlen * layer;\n\n\t\t\t// Bottom faces\n\n\t\t\tfor ( i = 0; i < flen; i ++ ) {\n\n\t\t\t\tface = faces[ i ];\n\t\t\t\tf3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset );\n\n\t\t\t}\n\n\t\t\tlayer = steps + bevelSegments * 2;\n\t\t\toffset = vlen * layer;\n\n\t\t\t// Top faces\n\n\t\t\tfor ( i = 0; i < flen; i ++ ) {\n\n\t\t\t\tface = faces[ i ];\n\t\t\t\tf3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// Bottom faces\n\n\t\t\tfor ( i = 0; i < flen; i ++ ) {\n\n\t\t\t\tface = faces[ i ];\n\t\t\t\tf3( face[ 2 ], face[ 1 ], face[ 0 ] );\n\n\t\t\t}\n\n\t\t\t// Top faces\n\n\t\t\tfor ( i = 0; i < flen; i ++ ) {\n\n\t\t\t\tface = faces[ i ];\n\t\t\t\tf3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t// Create faces for the z-sides of the shape\n\n\tfunction buildSideFaces() {\n\n\t\tvar layeroffset = 0;\n\t\tsidewalls( contour, layeroffset );\n\t\tlayeroffset += contour.length;\n\n\t\tfor ( h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\tahole = holes[ h ];\n\t\t\tsidewalls( ahole, layeroffset );\n\n\t\t\t//, true\n\t\t\tlayeroffset += ahole.length;\n\n\t\t}\n\n\t}\n\n\tfunction sidewalls( contour, layeroffset ) {\n\n\t\tvar j, k;\n\t\ti = contour.length;\n\n\t\twhile ( -- i >= 0 ) {\n\n\t\t\tj = i;\n\t\t\tk = i - 1;\n\t\t\tif ( k < 0 ) k = contour.length - 1;\n\n\t\t\t//console.log('b', i,j, i-1, k,vertices.length);\n\n\t\t\tvar s = 0, sl = steps + bevelSegments * 2;\n\n\t\t\tfor ( s = 0; s < sl; s ++ ) {\n\n\t\t\t\tvar slen1 = vlen * s;\n\t\t\t\tvar slen2 = vlen * ( s + 1 );\n\n\t\t\t\tvar a = layeroffset + j + slen1,\n\t\t\t\t\tb = layeroffset + k + slen1,\n\t\t\t\t\tc = layeroffset + k + slen2,\n\t\t\t\t\td = layeroffset + j + slen2;\n\n\t\t\t\tf4( a, b, c, d, contour, s, sl, j, k );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\n\tfunction v( x, y, z ) {\n\n\t\tscope.vertices.push( new Vector3( x, y, z ) );\n\n\t}\n\n\tfunction f3( a, b, c ) {\n\n\t\ta += shapesOffset;\n\t\tb += shapesOffset;\n\t\tc += shapesOffset;\n\n\t\tscope.faces.push( new Face3( a, b, c, null, null, 0 ) );\n\n\t\tvar uvs = uvgen.generateTopUV( scope, a, b, c );\n\n\t\tscope.faceVertexUvs[ 0 ].push( uvs );\n\n\t}\n\n\tfunction f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) {\n\n\t\ta += shapesOffset;\n\t\tb += shapesOffset;\n\t\tc += shapesOffset;\n\t\td += shapesOffset;\n\n\t\tscope.faces.push( new Face3( a, b, d, null, null, 1 ) );\n\t\tscope.faces.push( new Face3( b, c, d, null, null, 1 ) );\n\n\t\tvar uvs = uvgen.generateSideWallUV( scope, a, b, c, d );\n\n\t\tscope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] );\n\t\tscope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] );\n\n\t}\n\n};\n\nExtrudeGeometry.WorldUVGenerator = {\n\n\tgenerateTopUV: function ( geometry, indexA, indexB, indexC ) {\n\n\t\tvar vertices = geometry.vertices;\n\n\t\tvar a = vertices[ indexA ];\n\t\tvar b = vertices[ indexB ];\n\t\tvar c = vertices[ indexC ];\n\n\t\treturn [\n\t\t\tnew Vector2( a.x, a.y ),\n\t\t\tnew Vector2( b.x, b.y ),\n\t\t\tnew Vector2( c.x, c.y )\n\t\t];\n\n\t},\n\n\tgenerateSideWallUV: function ( geometry, indexA, indexB, indexC, indexD ) {\n\n\t\tvar vertices = geometry.vertices;\n\n\t\tvar a = vertices[ indexA ];\n\t\tvar b = vertices[ indexB ];\n\t\tvar c = vertices[ indexC ];\n\t\tvar d = vertices[ indexD ];\n\n\t\tif ( Math.abs( a.y - b.y ) < 0.01 ) {\n\n\t\t\treturn [\n\t\t\t\tnew Vector2( a.x, 1 - a.z ),\n\t\t\t\tnew Vector2( b.x, 1 - b.z ),\n\t\t\t\tnew Vector2( c.x, 1 - c.z ),\n\t\t\t\tnew Vector2( d.x, 1 - d.z )\n\t\t\t];\n\n\t\t} else {\n\n\t\t\treturn [\n\t\t\t\tnew Vector2( a.y, 1 - a.z ),\n\t\t\t\tnew Vector2( b.y, 1 - b.z ),\n\t\t\t\tnew Vector2( c.y, 1 - c.z ),\n\t\t\t\tnew Vector2( d.y, 1 - d.z )\n\t\t\t];\n\n\t\t}\n\n\t}\n};\n\n/**\n * @author zz85 / http://www.lab4games.net/zz85/blog\n * @author alteredq / http://alteredqualia.com/\n *\n * Text = 3D Text\n *\n * parameters = {\n * font: , // font\n *\n * size: , // size of the text\n * height: , // thickness to extrude text\n * curveSegments: , // number of points on the curves\n *\n * bevelEnabled: , // turn on bevel\n * bevelThickness: , // how deep into text bevel goes\n * bevelSize: // how far from text outline is bevel\n * }\n */\n\nfunction TextGeometry( text, parameters ) {\n\n\tparameters = parameters || {};\n\n\tvar font = parameters.font;\n\n\tif ( ( font && font.isFont ) === false ) {\n\n\t\tconsole.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' );\n\t\treturn new Geometry();\n\n\t}\n\n\tvar shapes = font.generateShapes( text, parameters.size, parameters.curveSegments );\n\n\t// translate parameters to ExtrudeGeometry API\n\n\tparameters.amount = parameters.height !== undefined ? parameters.height : 50;\n\n\t// defaults\n\n\tif ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;\n\tif ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;\n\tif ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;\n\n\tExtrudeGeometry.call( this, shapes, parameters );\n\n\tthis.type = 'TextGeometry';\n\n}\n\nTextGeometry.prototype = Object.create( ExtrudeGeometry.prototype );\nTextGeometry.prototype.constructor = TextGeometry;\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {\n\n\tGeometry.call( this );\n\n\tthis.type = 'SphereGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\twidthSegments: widthSegments,\n\t\theightSegments: heightSegments,\n\t\tphiStart: phiStart,\n\t\tphiLength: phiLength,\n\t\tthetaStart: thetaStart,\n\t\tthetaLength: thetaLength\n\t};\n\n\tthis.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) );\n\n}\n\nSphereGeometry.prototype = Object.create( Geometry.prototype );\nSphereGeometry.prototype.constructor = SphereGeometry;\n\n/**\n * @author benaadams / https://twitter.com/ben_a_adams\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {\n\n\tBufferGeometry.call( this );\n\n\tthis.type = 'SphereBufferGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\twidthSegments: widthSegments,\n\t\theightSegments: heightSegments,\n\t\tphiStart: phiStart,\n\t\tphiLength: phiLength,\n\t\tthetaStart: thetaStart,\n\t\tthetaLength: thetaLength\n\t};\n\n\tradius = radius || 50;\n\n\twidthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 );\n\theightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 );\n\n\tphiStart = phiStart !== undefined ? phiStart : 0;\n\tphiLength = phiLength !== undefined ? phiLength : Math.PI * 2;\n\n\tthetaStart = thetaStart !== undefined ? thetaStart : 0;\n\tthetaLength = thetaLength !== undefined ? thetaLength : Math.PI;\n\n\tvar thetaEnd = thetaStart + thetaLength;\n\n\tvar ix, iy;\n\n\tvar index = 0;\n\tvar grid = [];\n\n\tvar vertex = new Vector3();\n\tvar normal = new Vector3();\n\n\t// buffers\n\n\tvar indices = [];\n\tvar vertices = [];\n\tvar normals = [];\n\tvar uvs = [];\n\n\t// generate vertices, normals and uvs\n\n\tfor ( iy = 0; iy <= heightSegments; iy ++ ) {\n\n\t\tvar verticesRow = [];\n\n\t\tvar v = iy / heightSegments;\n\n\t\tfor ( ix = 0; ix <= widthSegments; ix ++ ) {\n\n\t\t\tvar u = ix / widthSegments;\n\n\t\t\t// vertex\n\n\t\t\tvertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );\n\t\t\tvertex.y = radius * Math.cos( thetaStart + v * thetaLength );\n\t\t\tvertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );\n\n\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t// normal\n\n\t\t\tnormal.set( vertex.x, vertex.y, vertex.z ).normalize();\n\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t// uv\n\n\t\t\tuvs.push( u, 1 - v );\n\n\t\t\tverticesRow.push( index ++ );\n\n\t\t}\n\n\t\tgrid.push( verticesRow );\n\n\t}\n\n\t// indices\n\n\tfor ( iy = 0; iy < heightSegments; iy ++ ) {\n\n\t\tfor ( ix = 0; ix < widthSegments; ix ++ ) {\n\n\t\t\tvar a = grid[ iy ][ ix + 1 ];\n\t\t\tvar b = grid[ iy ][ ix ];\n\t\t\tvar c = grid[ iy + 1 ][ ix ];\n\t\t\tvar d = grid[ iy + 1 ][ ix + 1 ];\n\n\t\t\tif ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );\n\t\t\tif ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );\n\n\t\t}\n\n\t}\n\n\t// build geometry\n\n\tthis.setIndex( indices );\n\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n}\n\nSphereBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\nSphereBufferGeometry.prototype.constructor = SphereBufferGeometry;\n\n/**\n * @author Kaleb Murphy\n */\n\nfunction RingGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {\n\n\tGeometry.call( this );\n\n\tthis.type = 'RingGeometry';\n\n\tthis.parameters = {\n\t\tinnerRadius: innerRadius,\n\t\touterRadius: outerRadius,\n\t\tthetaSegments: thetaSegments,\n\t\tphiSegments: phiSegments,\n\t\tthetaStart: thetaStart,\n\t\tthetaLength: thetaLength\n\t};\n\n\tthis.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) );\n\n}\n\nRingGeometry.prototype = Object.create( Geometry.prototype );\nRingGeometry.prototype.constructor = RingGeometry;\n\n/**\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {\n\n\tBufferGeometry.call( this );\n\n\tthis.type = 'RingBufferGeometry';\n\n\tthis.parameters = {\n\t\tinnerRadius: innerRadius,\n\t\touterRadius: outerRadius,\n\t\tthetaSegments: thetaSegments,\n\t\tphiSegments: phiSegments,\n\t\tthetaStart: thetaStart,\n\t\tthetaLength: thetaLength\n\t};\n\n\tinnerRadius = innerRadius || 20;\n\touterRadius = outerRadius || 50;\n\n\tthetaStart = thetaStart !== undefined ? thetaStart : 0;\n\tthetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;\n\n\tthetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8;\n\tphiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 1;\n\n\t// buffers\n\n\tvar indices = [];\n\tvar vertices = [];\n\tvar normals = [];\n\tvar uvs = [];\n\n\t// some helper variables\n\n\tvar segment;\n\tvar radius = innerRadius;\n\tvar radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );\n\tvar vertex = new Vector3();\n\tvar uv = new Vector2();\n\tvar j, i;\n\n\t// generate vertices, normals and uvs\n\n\tfor ( j = 0; j <= phiSegments; j ++ ) {\n\n\t\tfor ( i = 0; i <= thetaSegments; i ++ ) {\n\n\t\t\t// values are generate from the inside of the ring to the outside\n\n\t\t\tsegment = thetaStart + i / thetaSegments * thetaLength;\n\n\t\t\t// vertex\n\n\t\t\tvertex.x = radius * Math.cos( segment );\n\t\t\tvertex.y = radius * Math.sin( segment );\n\n\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t// normal\n\n\t\t\tnormals.push( 0, 0, 1 );\n\n\t\t\t// uv\n\n\t\t\tuv.x = ( vertex.x / outerRadius + 1 ) / 2;\n\t\t\tuv.y = ( vertex.y / outerRadius + 1 ) / 2;\n\n\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t}\n\n\t\t// increase the radius for next row of vertices\n\n\t\tradius += radiusStep;\n\n\t}\n\n\t// indices\n\n\tfor ( j = 0; j < phiSegments; j ++ ) {\n\n\t\tvar thetaSegmentLevel = j * ( thetaSegments + 1 );\n\n\t\tfor ( i = 0; i < thetaSegments; i ++ ) {\n\n\t\t\tsegment = i + thetaSegmentLevel;\n\n\t\t\tvar a = segment;\n\t\t\tvar b = segment + thetaSegments + 1;\n\t\t\tvar c = segment + thetaSegments + 2;\n\t\t\tvar d = segment + 1;\n\n\t\t\t// faces\n\n\t\t\tindices.push( a, b, d );\n\t\t\tindices.push( b, c, d );\n\n\t\t}\n\n\t}\n\n\t// build geometry\n\n\tthis.setIndex( indices );\n\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n}\n\nRingBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\nRingBufferGeometry.prototype.constructor = RingBufferGeometry;\n\n/**\n * @author astrodud / http://astrodud.isgreat.org/\n * @author zz85 / https://github.com/zz85\n * @author bhouston / http://clara.io\n */\n\n// points - to create a closed torus, one must use a set of points\n// like so: [ a, b, c, d, a ], see first is the same as last.\n// segments - the number of circumference segments to create\n// phiStart - the starting radian\n// phiLength - the radian (0 to 2PI) range of the lathed section\n// 2PI is a closed lathe, less than 2PI is a portion.\n\nfunction LatheGeometry( points, segments, phiStart, phiLength ) {\n\n\tGeometry.call( this );\n\n\tthis.type = 'LatheGeometry';\n\n\tthis.parameters = {\n\t\tpoints: points,\n\t\tsegments: segments,\n\t\tphiStart: phiStart,\n\t\tphiLength: phiLength\n\t};\n\n\tthis.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) );\n\tthis.mergeVertices();\n\n}\n\nLatheGeometry.prototype = Object.create( Geometry.prototype );\nLatheGeometry.prototype.constructor = LatheGeometry;\n\n/**\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction LatheBufferGeometry( points, segments, phiStart, phiLength ) {\n\n\tBufferGeometry.call( this );\n\n\tthis.type = 'LatheBufferGeometry';\n\n\tthis.parameters = {\n\t\tpoints: points,\n\t\tsegments: segments,\n\t\tphiStart: phiStart,\n\t\tphiLength: phiLength\n\t};\n\n\tsegments = Math.floor( segments ) || 12;\n\tphiStart = phiStart || 0;\n\tphiLength = phiLength || Math.PI * 2;\n\n\t// clamp phiLength so it's in range of [ 0, 2PI ]\n\n\tphiLength = _Math.clamp( phiLength, 0, Math.PI * 2 );\n\n\n\t// buffers\n\n\tvar indices = [];\n\tvar vertices = [];\n\tvar uvs = [];\n\n\t// helper variables\n\n\tvar base;\n\tvar inverseSegments = 1.0 / segments;\n\tvar vertex = new Vector3();\n\tvar uv = new Vector2();\n\tvar i, j;\n\n\t// generate vertices and uvs\n\n\tfor ( i = 0; i <= segments; i ++ ) {\n\n\t\tvar phi = phiStart + i * inverseSegments * phiLength;\n\n\t\tvar sin = Math.sin( phi );\n\t\tvar cos = Math.cos( phi );\n\n\t\tfor ( j = 0; j <= ( points.length - 1 ); j ++ ) {\n\n\t\t\t// vertex\n\n\t\t\tvertex.x = points[ j ].x * sin;\n\t\t\tvertex.y = points[ j ].y;\n\t\t\tvertex.z = points[ j ].x * cos;\n\n\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t// uv\n\n\t\t\tuv.x = i / segments;\n\t\t\tuv.y = j / ( points.length - 1 );\n\n\t\t\tuvs.push( uv.x, uv.y );\n\n\n\t\t}\n\n\t}\n\n\t// indices\n\n\tfor ( i = 0; i < segments; i ++ ) {\n\n\t\tfor ( j = 0; j < ( points.length - 1 ); j ++ ) {\n\n\t\t\tbase = j + i * points.length;\n\n\t\t\tvar a = base;\n\t\t\tvar b = base + points.length;\n\t\t\tvar c = base + points.length + 1;\n\t\t\tvar d = base + 1;\n\n\t\t\t// faces\n\n\t\t\tindices.push( a, b, d );\n\t\t\tindices.push( b, c, d );\n\n\t\t}\n\n\t}\n\n\t// build geometry\n\n\tthis.setIndex( indices );\n\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t// generate normals\n\n\tthis.computeVertexNormals();\n\n\t// if the geometry is closed, we need to average the normals along the seam.\n\t// because the corresponding vertices are identical (but still have different UVs).\n\n\tif ( phiLength === Math.PI * 2 ) {\n\n\t\tvar normals = this.attributes.normal.array;\n\t\tvar n1 = new Vector3();\n\t\tvar n2 = new Vector3();\n\t\tvar n = new Vector3();\n\n\t\t// this is the buffer offset for the last line of vertices\n\n\t\tbase = segments * points.length * 3;\n\n\t\tfor ( i = 0, j = 0; i < points.length; i ++, j += 3 ) {\n\n\t\t\t// select the normal of the vertex in the first line\n\n\t\t\tn1.x = normals[ j + 0 ];\n\t\t\tn1.y = normals[ j + 1 ];\n\t\t\tn1.z = normals[ j + 2 ];\n\n\t\t\t// select the normal of the vertex in the last line\n\n\t\t\tn2.x = normals[ base + j + 0 ];\n\t\t\tn2.y = normals[ base + j + 1 ];\n\t\t\tn2.z = normals[ base + j + 2 ];\n\n\t\t\t// average normals\n\n\t\t\tn.addVectors( n1, n2 ).normalize();\n\n\t\t\t// assign the new values to both normals\n\n\t\t\tnormals[ j + 0 ] = normals[ base + j + 0 ] = n.x;\n\t\t\tnormals[ j + 1 ] = normals[ base + j + 1 ] = n.y;\n\t\t\tnormals[ j + 2 ] = normals[ base + j + 2 ] = n.z;\n\n\t\t}\n\n\t}\n\n}\n\nLatheBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\nLatheBufferGeometry.prototype.constructor = LatheBufferGeometry;\n\n/**\n * @author jonobr1 / http://jonobr1.com\n */\n\nfunction ShapeGeometry( shapes, curveSegments ) {\n\n\tGeometry.call( this );\n\n\tthis.type = 'ShapeGeometry';\n\n\tif ( typeof curveSegments === 'object' ) {\n\n\t\tconsole.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' );\n\n\t\tcurveSegments = curveSegments.curveSegments;\n\n\t}\n\n\tthis.parameters = {\n\t\tshapes: shapes,\n\t\tcurveSegments: curveSegments\n\t};\n\n\tthis.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) );\n\tthis.mergeVertices();\n\n}\n\nShapeGeometry.prototype = Object.create( Geometry.prototype );\nShapeGeometry.prototype.constructor = ShapeGeometry;\n\n/**\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction ShapeBufferGeometry( shapes, curveSegments ) {\n\n\tBufferGeometry.call( this );\n\n\tthis.type = 'ShapeBufferGeometry';\n\n\tthis.parameters = {\n\t\tshapes: shapes,\n\t\tcurveSegments: curveSegments\n\t};\n\n\tcurveSegments = curveSegments || 12;\n\n\t// buffers\n\n\tvar indices = [];\n\tvar vertices = [];\n\tvar normals = [];\n\tvar uvs = [];\n\n\t// helper variables\n\n\tvar groupStart = 0;\n\tvar groupCount = 0;\n\n\t// allow single and array values for \"shapes\" parameter\n\n\tif ( Array.isArray( shapes ) === false ) {\n\n\t\taddShape( shapes );\n\n\t} else {\n\n\t\tfor ( var i = 0; i < shapes.length; i ++ ) {\n\n\t\t\taddShape( shapes[ i ] );\n\n\t\t\tthis.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support\n\n\t\t\tgroupStart += groupCount;\n\t\t\tgroupCount = 0;\n\n\t\t}\n\n\t}\n\n\t// build geometry\n\n\tthis.setIndex( indices );\n\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\n\t// helper functions\n\n\tfunction addShape( shape ) {\n\n\t\tvar i, l, shapeHole;\n\n\t\tvar indexOffset = vertices.length / 3;\n\t\tvar points = shape.extractPoints( curveSegments );\n\n\t\tvar shapeVertices = points.shape;\n\t\tvar shapeHoles = points.holes;\n\n\t\t// check direction of vertices\n\n\t\tif ( ShapeUtils.isClockWise( shapeVertices ) === false ) {\n\n\t\t\tshapeVertices = shapeVertices.reverse();\n\n\t\t\t// also check if holes are in the opposite direction\n\n\t\t\tfor ( i = 0, l = shapeHoles.length; i < l; i ++ ) {\n\n\t\t\t\tshapeHole = shapeHoles[ i ];\n\n\t\t\t\tif ( ShapeUtils.isClockWise( shapeHole ) === true ) {\n\n\t\t\t\t\tshapeHoles[ i ] = shapeHole.reverse();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );\n\n\t\t// join vertices of inner and outer paths to a single array\n\n\t\tfor ( i = 0, l = shapeHoles.length; i < l; i ++ ) {\n\n\t\t\tshapeHole = shapeHoles[ i ];\n\t\t\tshapeVertices = shapeVertices.concat( shapeHole );\n\n\t\t}\n\n\t\t// vertices, normals, uvs\n\n\t\tfor ( i = 0, l = shapeVertices.length; i < l; i ++ ) {\n\n\t\t\tvar vertex = shapeVertices[ i ];\n\n\t\t\tvertices.push( vertex.x, vertex.y, 0 );\n\t\t\tnormals.push( 0, 0, 1 );\n\t\t\tuvs.push( vertex.x, vertex.y ); // world uvs\n\n\t\t}\n\n\t\t// incides\n\n\t\tfor ( i = 0, l = faces.length; i < l; i ++ ) {\n\n\t\t\tvar face = faces[ i ];\n\n\t\t\tvar a = face[ 0 ] + indexOffset;\n\t\t\tvar b = face[ 1 ] + indexOffset;\n\t\t\tvar c = face[ 2 ] + indexOffset;\n\n\t\t\tindices.push( a, b, c );\n\t\t\tgroupCount += 3;\n\n\t\t}\n\n\t}\n\n}\n\nShapeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\nShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry;\n\n/**\n * @author WestLangley / http://github.com/WestLangley\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction EdgesGeometry( geometry, thresholdAngle ) {\n\n\tBufferGeometry.call( this );\n\n\tthis.type = 'EdgesGeometry';\n\n\tthis.parameters = {\n\t\tthresholdAngle: thresholdAngle\n\t};\n\n\tthresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1;\n\n\t// buffer\n\n\tvar vertices = [];\n\n\t// helper variables\n\n\tvar thresholdDot = Math.cos( _Math.DEG2RAD * thresholdAngle );\n\tvar edge = [ 0, 0 ], edges = {};\n\tvar key, keys = [ 'a', 'b', 'c' ];\n\n\t// prepare source geometry\n\n\tvar geometry2;\n\n\tif ( geometry.isBufferGeometry ) {\n\n\t\tgeometry2 = new Geometry();\n\t\tgeometry2.fromBufferGeometry( geometry );\n\n\t} else {\n\n\t\tgeometry2 = geometry.clone();\n\n\t}\n\n\tgeometry2.mergeVertices();\n\tgeometry2.computeFaceNormals();\n\n\tvar sourceVertices = geometry2.vertices;\n\tvar faces = geometry2.faces;\n\n\t// now create a data structure where each entry represents an edge with its adjoining faces\n\n\tfor ( var i = 0, l = faces.length; i < l; i ++ ) {\n\n\t\tvar face = faces[ i ];\n\n\t\tfor ( var j = 0; j < 3; j ++ ) {\n\n\t\t\tedge[ 0 ] = face[ keys[ j ] ];\n\t\t\tedge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ];\n\t\t\tedge.sort( sortFunction );\n\n\t\t\tkey = edge.toString();\n\n\t\t\tif ( edges[ key ] === undefined ) {\n\n\t\t\t\tedges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ], face1: i, face2: undefined };\n\n\t\t\t} else {\n\n\t\t\t\tedges[ key ].face2 = i;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t// generate vertices\n\n\tfor ( key in edges ) {\n\n\t\tvar e = edges[ key ];\n\n\t\t// an edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree.\n\n\t\tif ( e.face2 === undefined || faces[ e.face1 ].normal.dot( faces[ e.face2 ].normal ) <= thresholdDot ) {\n\n\t\t\tvar vertex = sourceVertices[ e.index1 ];\n\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\tvertex = sourceVertices[ e.index2 ];\n\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t}\n\n\t}\n\n\t// build geometry\n\n\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\n\t// custom array sort function\n\n\tfunction sortFunction( a, b ) {\n\n\t\treturn a - b;\n\n\t}\n\n}\n\nEdgesGeometry.prototype = Object.create( BufferGeometry.prototype );\nEdgesGeometry.prototype.constructor = EdgesGeometry;\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {\n\n\tGeometry.call( this );\n\n\tthis.type = 'CylinderGeometry';\n\n\tthis.parameters = {\n\t\tradiusTop: radiusTop,\n\t\tradiusBottom: radiusBottom,\n\t\theight: height,\n\t\tradialSegments: radialSegments,\n\t\theightSegments: heightSegments,\n\t\topenEnded: openEnded,\n\t\tthetaStart: thetaStart,\n\t\tthetaLength: thetaLength\n\t};\n\n\tthis.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) );\n\tthis.mergeVertices();\n\n}\n\nCylinderGeometry.prototype = Object.create( Geometry.prototype );\nCylinderGeometry.prototype.constructor = CylinderGeometry;\n\n/**\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {\n\n\tBufferGeometry.call( this );\n\n\tthis.type = 'CylinderBufferGeometry';\n\n\tthis.parameters = {\n\t\tradiusTop: radiusTop,\n\t\tradiusBottom: radiusBottom,\n\t\theight: height,\n\t\tradialSegments: radialSegments,\n\t\theightSegments: heightSegments,\n\t\topenEnded: openEnded,\n\t\tthetaStart: thetaStart,\n\t\tthetaLength: thetaLength\n\t};\n\n\tvar scope = this;\n\n\tradiusTop = radiusTop !== undefined ? radiusTop : 20;\n\tradiusBottom = radiusBottom !== undefined ? radiusBottom : 20;\n\theight = height !== undefined ? height : 100;\n\n\tradialSegments = Math.floor( radialSegments ) || 8;\n\theightSegments = Math.floor( heightSegments ) || 1;\n\n\topenEnded = openEnded !== undefined ? openEnded : false;\n\tthetaStart = thetaStart !== undefined ? thetaStart : 0.0;\n\tthetaLength = thetaLength !== undefined ? thetaLength : 2.0 * Math.PI;\n\n\t// buffers\n\n\tvar indices = [];\n\tvar vertices = [];\n\tvar normals = [];\n\tvar uvs = [];\n\n\t// helper variables\n\n\tvar index = 0;\n\tvar indexOffset = 0;\n\tvar indexArray = [];\n\tvar halfHeight = height / 2;\n\tvar groupStart = 0;\n\n\t// generate geometry\n\n\tgenerateTorso();\n\n\tif ( openEnded === false ) {\n\n\t\tif ( radiusTop > 0 ) generateCap( true );\n\t\tif ( radiusBottom > 0 ) generateCap( false );\n\n\t}\n\n\t// build geometry\n\n\tthis.setIndex( indices );\n\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\tfunction generateTorso() {\n\n\t\tvar x, y;\n\t\tvar normal = new Vector3();\n\t\tvar vertex = new Vector3();\n\n\t\tvar groupCount = 0;\n\n\t\t// this will be used to calculate the normal\n\t\tvar slope = ( radiusBottom - radiusTop ) / height;\n\n\t\t// generate vertices, normals and uvs\n\n\t\tfor ( y = 0; y <= heightSegments; y ++ ) {\n\n\t\t\tvar indexRow = [];\n\n\t\t\tvar v = y / heightSegments;\n\n\t\t\t// calculate the radius of the current row\n\n\t\t\tvar radius = v * ( radiusBottom - radiusTop ) + radiusTop;\n\n\t\t\tfor ( x = 0; x <= radialSegments; x ++ ) {\n\n\t\t\t\tvar u = x / radialSegments;\n\n\t\t\t\tvar theta = u * thetaLength + thetaStart;\n\n\t\t\t\tvar sinTheta = Math.sin( theta );\n\t\t\t\tvar cosTheta = Math.cos( theta );\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = radius * sinTheta;\n\t\t\t\tvertex.y = - v * height + halfHeight;\n\t\t\t\tvertex.z = radius * cosTheta;\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// normal\n\n\t\t\t\tnormal.set( sinTheta, slope, cosTheta ).normalize();\n\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t// uv\n\n\t\t\t\tuvs.push( u, 1 - v );\n\n\t\t\t\t// save index of vertex in respective row\n\n\t\t\t\tindexRow.push( index ++ );\n\n\t\t\t}\n\n\t\t\t// now save vertices of the row in our index array\n\n\t\t\tindexArray.push( indexRow );\n\n\t\t}\n\n\t\t// generate indices\n\n\t\tfor ( x = 0; x < radialSegments; x ++ ) {\n\n\t\t\tfor ( y = 0; y < heightSegments; y ++ ) {\n\n\t\t\t\t// we use the index array to access the correct indices\n\n\t\t\t\tvar a = indexArray[ y ][ x ];\n\t\t\t\tvar b = indexArray[ y + 1 ][ x ];\n\t\t\t\tvar c = indexArray[ y + 1 ][ x + 1 ];\n\t\t\t\tvar d = indexArray[ y ][ x + 1 ];\n\n\t\t\t\t// faces\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( b, c, d );\n\n\t\t\t\t// update group counter\n\n\t\t\t\tgroupCount += 6;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// add a group to the geometry. this will ensure multi material support\n\n\t\tscope.addGroup( groupStart, groupCount, 0 );\n\n\t\t// calculate new start value for groups\n\n\t\tgroupStart += groupCount;\n\n\t}\n\n\tfunction generateCap( top ) {\n\n\t\tvar x, centerIndexStart, centerIndexEnd;\n\n\t\tvar uv = new Vector2();\n\t\tvar vertex = new Vector3();\n\n\t\tvar groupCount = 0;\n\n\t\tvar radius = ( top === true ) ? radiusTop : radiusBottom;\n\t\tvar sign = ( top === true ) ? 1 : - 1;\n\n\t\t// save the index of the first center vertex\n\t\tcenterIndexStart = index;\n\n\t\t// first we generate the center vertex data of the cap.\n\t\t// because the geometry needs one set of uvs per face,\n\t\t// we must generate a center vertex per face/segment\n\n\t\tfor ( x = 1; x <= radialSegments; x ++ ) {\n\n\t\t\t// vertex\n\n\t\t\tvertices.push( 0, halfHeight * sign, 0 );\n\n\t\t\t// normal\n\n\t\t\tnormals.push( 0, sign, 0 );\n\n\t\t\t// uv\n\n\t\t\tuvs.push( 0.5, 0.5 );\n\n\t\t\t// increase index\n\n\t\t\tindex ++;\n\n\t\t}\n\n\t\t// save the index of the last center vertex\n\n\t\tcenterIndexEnd = index;\n\n\t\t// now we generate the surrounding vertices, normals and uvs\n\n\t\tfor ( x = 0; x <= radialSegments; x ++ ) {\n\n\t\t\tvar u = x / radialSegments;\n\t\t\tvar theta = u * thetaLength + thetaStart;\n\n\t\t\tvar cosTheta = Math.cos( theta );\n\t\t\tvar sinTheta = Math.sin( theta );\n\n\t\t\t// vertex\n\n\t\t\tvertex.x = radius * sinTheta;\n\t\t\tvertex.y = halfHeight * sign;\n\t\t\tvertex.z = radius * cosTheta;\n\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t// normal\n\n\t\t\tnormals.push( 0, sign, 0 );\n\n\t\t\t// uv\n\n\t\t\tuv.x = ( cosTheta * 0.5 ) + 0.5;\n\t\t\tuv.y = ( sinTheta * 0.5 * sign ) + 0.5;\n\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t\t// increase index\n\n\t\t\tindex ++;\n\n\t\t}\n\n\t\t// generate indices\n\n\t\tfor ( x = 0; x < radialSegments; x ++ ) {\n\n\t\t\tvar c = centerIndexStart + x;\n\t\t\tvar i = centerIndexEnd + x;\n\n\t\t\tif ( top === true ) {\n\n\t\t\t\t// face top\n\n\t\t\t\tindices.push( i, i + 1, c );\n\n\t\t\t} else {\n\n\t\t\t\t// face bottom\n\n\t\t\t\tindices.push( i + 1, i, c );\n\n\t\t\t}\n\n\t\t\tgroupCount += 3;\n\n\t\t}\n\n\t\t// add a group to the geometry. this will ensure multi material support\n\n\t\tscope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );\n\n\t\t// calculate new start value for groups\n\n\t\tgroupStart += groupCount;\n\n\t}\n\n}\n\nCylinderBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\nCylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry;\n\n/**\n * @author abelnation / http://github.com/abelnation\n */\n\nfunction ConeGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {\n\n\tCylinderGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );\n\n\tthis.type = 'ConeGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\theight: height,\n\t\tradialSegments: radialSegments,\n\t\theightSegments: heightSegments,\n\t\topenEnded: openEnded,\n\t\tthetaStart: thetaStart,\n\t\tthetaLength: thetaLength\n\t};\n\n}\n\nConeGeometry.prototype = Object.create( CylinderGeometry.prototype );\nConeGeometry.prototype.constructor = ConeGeometry;\n\n/**\n * @author: abelnation / http://github.com/abelnation\n */\n\nfunction ConeBufferGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {\n\n\tCylinderBufferGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );\n\n\tthis.type = 'ConeBufferGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\theight: height,\n\t\tradialSegments: radialSegments,\n\t\theightSegments: heightSegments,\n\t\topenEnded: openEnded,\n\t\tthetaStart: thetaStart,\n\t\tthetaLength: thetaLength\n\t};\n\n}\n\nConeBufferGeometry.prototype = Object.create( CylinderBufferGeometry.prototype );\nConeBufferGeometry.prototype.constructor = ConeBufferGeometry;\n\n/**\n * @author hughes\n */\n\nfunction CircleGeometry( radius, segments, thetaStart, thetaLength ) {\n\n\tGeometry.call( this );\n\n\tthis.type = 'CircleGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\tsegments: segments,\n\t\tthetaStart: thetaStart,\n\t\tthetaLength: thetaLength\n\t};\n\n\tthis.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) );\n\n}\n\nCircleGeometry.prototype = Object.create( Geometry.prototype );\nCircleGeometry.prototype.constructor = CircleGeometry;\n\n/**\n * @author benaadams / https://twitter.com/ben_a_adams\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) {\n\n\tBufferGeometry.call( this );\n\n\tthis.type = 'CircleBufferGeometry';\n\n\tthis.parameters = {\n\t\tradius: radius,\n\t\tsegments: segments,\n\t\tthetaStart: thetaStart,\n\t\tthetaLength: thetaLength\n\t};\n\n\tradius = radius || 50;\n\tsegments = segments !== undefined ? Math.max( 3, segments ) : 8;\n\n\tthetaStart = thetaStart !== undefined ? thetaStart : 0;\n\tthetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;\n\n\t// buffers\n\n\tvar indices = [];\n\tvar vertices = [];\n\tvar normals = [];\n\tvar uvs = [];\n\n\t// helper variables\n\n\tvar i, s;\n\tvar vertex = new Vector3();\n\tvar uv = new Vector2();\n\n\t// center point\n\n\tvertices.push( 0, 0, 0 );\n\tnormals.push( 0, 0, 1 );\n\tuvs.push( 0.5, 0.5 );\n\n\tfor ( s = 0, i = 3; s <= segments; s ++, i += 3 ) {\n\n\t\tvar segment = thetaStart + s / segments * thetaLength;\n\n\t\t// vertex\n\n\t\tvertex.x = radius * Math.cos( segment );\n\t\tvertex.y = radius * Math.sin( segment );\n\n\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t// normal\n\n\t\tnormals.push( 0, 0, 1 );\n\n\t\t// uvs\n\n\t\tuv.x = ( vertices[ i ] / radius + 1 ) / 2;\n\t\tuv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;\n\n\t\tuvs.push( uv.x, uv.y );\n\n\t}\n\n\t// indices\n\n\tfor ( i = 1; i <= segments; i ++ ) {\n\n\t\tindices.push( i, i + 1, 0 );\n\n\t}\n\n\t// build geometry\n\n\tthis.setIndex( indices );\n\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n}\n\nCircleBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\nCircleBufferGeometry.prototype.constructor = CircleBufferGeometry;\n\n\n\nvar Geometries = Object.freeze({\n\tWireframeGeometry: WireframeGeometry,\n\tParametricGeometry: ParametricGeometry,\n\tParametricBufferGeometry: ParametricBufferGeometry,\n\tTetrahedronGeometry: TetrahedronGeometry,\n\tTetrahedronBufferGeometry: TetrahedronBufferGeometry,\n\tOctahedronGeometry: OctahedronGeometry,\n\tOctahedronBufferGeometry: OctahedronBufferGeometry,\n\tIcosahedronGeometry: IcosahedronGeometry,\n\tIcosahedronBufferGeometry: IcosahedronBufferGeometry,\n\tDodecahedronGeometry: DodecahedronGeometry,\n\tDodecahedronBufferGeometry: DodecahedronBufferGeometry,\n\tPolyhedronGeometry: PolyhedronGeometry,\n\tPolyhedronBufferGeometry: PolyhedronBufferGeometry,\n\tTubeGeometry: TubeGeometry,\n\tTubeBufferGeometry: TubeBufferGeometry,\n\tTorusKnotGeometry: TorusKnotGeometry,\n\tTorusKnotBufferGeometry: TorusKnotBufferGeometry,\n\tTorusGeometry: TorusGeometry,\n\tTorusBufferGeometry: TorusBufferGeometry,\n\tTextGeometry: TextGeometry,\n\tSphereGeometry: SphereGeometry,\n\tSphereBufferGeometry: SphereBufferGeometry,\n\tRingGeometry: RingGeometry,\n\tRingBufferGeometry: RingBufferGeometry,\n\tPlaneGeometry: PlaneGeometry,\n\tPlaneBufferGeometry: PlaneBufferGeometry,\n\tLatheGeometry: LatheGeometry,\n\tLatheBufferGeometry: LatheBufferGeometry,\n\tShapeGeometry: ShapeGeometry,\n\tShapeBufferGeometry: ShapeBufferGeometry,\n\tExtrudeGeometry: ExtrudeGeometry,\n\tEdgesGeometry: EdgesGeometry,\n\tConeGeometry: ConeGeometry,\n\tConeBufferGeometry: ConeBufferGeometry,\n\tCylinderGeometry: CylinderGeometry,\n\tCylinderBufferGeometry: CylinderBufferGeometry,\n\tCircleGeometry: CircleGeometry,\n\tCircleBufferGeometry: CircleBufferGeometry,\n\tBoxGeometry: BoxGeometry,\n\tBoxBufferGeometry: BoxBufferGeometry\n});\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction ShadowMaterial() {\n\n\tShaderMaterial.call( this, {\n\t\tuniforms: UniformsUtils.merge( [\n\t\t\tUniformsLib.lights,\n\t\t\t{\n\t\t\t\topacity: { value: 1.0 }\n\t\t\t}\n\t\t] ),\n\t\tvertexShader: ShaderChunk[ 'shadow_vert' ],\n\t\tfragmentShader: ShaderChunk[ 'shadow_frag' ]\n\t} );\n\n\tthis.lights = true;\n\tthis.transparent = true;\n\n\tObject.defineProperties( this, {\n\t\topacity: {\n\t\t\tenumerable: true,\n\t\t\tget: function () {\n\t\t\t\treturn this.uniforms.opacity.value;\n\t\t\t},\n\t\t\tset: function ( value ) {\n\t\t\t\tthis.uniforms.opacity.value = value;\n\t\t\t}\n\t\t}\n\t} );\n\n}\n\nShadowMaterial.prototype = Object.create( ShaderMaterial.prototype );\nShadowMaterial.prototype.constructor = ShadowMaterial;\n\nShadowMaterial.prototype.isShadowMaterial = true;\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction RawShaderMaterial( parameters ) {\n\n\tShaderMaterial.call( this, parameters );\n\n\tthis.type = 'RawShaderMaterial';\n\n}\n\nRawShaderMaterial.prototype = Object.create( ShaderMaterial.prototype );\nRawShaderMaterial.prototype.constructor = RawShaderMaterial;\n\nRawShaderMaterial.prototype.isRawShaderMaterial = true;\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction MultiMaterial( materials ) {\n\n\tthis.uuid = _Math.generateUUID();\n\n\tthis.type = 'MultiMaterial';\n\n\tthis.materials = Array.isArray( materials ) ? materials : [];\n\n\tthis.visible = true;\n\n}\n\nMultiMaterial.prototype = {\n\n\tconstructor: MultiMaterial,\n\n\tisMultiMaterial: true,\n\n\ttoJSON: function ( meta ) {\n\n\t\tvar output = {\n\t\t\tmetadata: {\n\t\t\t\tversion: 4.2,\n\t\t\t\ttype: 'material',\n\t\t\t\tgenerator: 'MaterialExporter'\n\t\t\t},\n\t\t\tuuid: this.uuid,\n\t\t\ttype: this.type,\n\t\t\tmaterials: []\n\t\t};\n\n\t\tvar materials = this.materials;\n\n\t\tfor ( var i = 0, l = materials.length; i < l; i ++ ) {\n\n\t\t\tvar material = materials[ i ].toJSON( meta );\n\t\t\tdelete material.metadata;\n\n\t\t\toutput.materials.push( material );\n\n\t\t}\n\n\t\toutput.visible = this.visible;\n\n\t\treturn output;\n\n\t},\n\n\tclone: function () {\n\n\t\tvar material = new this.constructor();\n\n\t\tfor ( var i = 0; i < this.materials.length; i ++ ) {\n\n\t\t\tmaterial.materials.push( this.materials[ i ].clone() );\n\n\t\t}\n\n\t\tmaterial.visible = this.visible;\n\n\t\treturn material;\n\n\t}\n\n};\n\n/**\n * @author WestLangley / http://github.com/WestLangley\n *\n * parameters = {\n * color: ,\n * roughness: ,\n * metalness: ,\n * opacity: ,\n *\n * map: new THREE.Texture( ),\n *\n * lightMap: new THREE.Texture( ),\n * lightMapIntensity: \n *\n * aoMap: new THREE.Texture( ),\n * aoMapIntensity: \n *\n * emissive: ,\n * emissiveIntensity: \n * emissiveMap: new THREE.Texture( ),\n *\n * bumpMap: new THREE.Texture( ),\n * bumpScale: ,\n *\n * normalMap: new THREE.Texture( ),\n * normalScale: ,\n *\n * displacementMap: new THREE.Texture( ),\n * displacementScale: ,\n * displacementBias: ,\n *\n * roughnessMap: new THREE.Texture( ),\n *\n * metalnessMap: new THREE.Texture( ),\n *\n * alphaMap: new THREE.Texture( ),\n *\n * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),\n * envMapIntensity: \n *\n * refractionRatio: ,\n *\n * wireframe: ,\n * wireframeLinewidth: ,\n *\n * skinning: ,\n * morphTargets: ,\n * morphNormals: \n * }\n */\n\nfunction MeshStandardMaterial( parameters ) {\n\n\tMaterial.call( this );\n\n\tthis.defines = { 'STANDARD': '' };\n\n\tthis.type = 'MeshStandardMaterial';\n\n\tthis.color = new Color( 0xffffff ); // diffuse\n\tthis.roughness = 0.5;\n\tthis.metalness = 0.5;\n\n\tthis.map = null;\n\n\tthis.lightMap = null;\n\tthis.lightMapIntensity = 1.0;\n\n\tthis.aoMap = null;\n\tthis.aoMapIntensity = 1.0;\n\n\tthis.emissive = new Color( 0x000000 );\n\tthis.emissiveIntensity = 1.0;\n\tthis.emissiveMap = null;\n\n\tthis.bumpMap = null;\n\tthis.bumpScale = 1;\n\n\tthis.normalMap = null;\n\tthis.normalScale = new Vector2( 1, 1 );\n\n\tthis.displacementMap = null;\n\tthis.displacementScale = 1;\n\tthis.displacementBias = 0;\n\n\tthis.roughnessMap = null;\n\n\tthis.metalnessMap = null;\n\n\tthis.alphaMap = null;\n\n\tthis.envMap = null;\n\tthis.envMapIntensity = 1.0;\n\n\tthis.refractionRatio = 0.98;\n\n\tthis.wireframe = false;\n\tthis.wireframeLinewidth = 1;\n\tthis.wireframeLinecap = 'round';\n\tthis.wireframeLinejoin = 'round';\n\n\tthis.skinning = false;\n\tthis.morphTargets = false;\n\tthis.morphNormals = false;\n\n\tthis.setValues( parameters );\n\n}\n\nMeshStandardMaterial.prototype = Object.create( Material.prototype );\nMeshStandardMaterial.prototype.constructor = MeshStandardMaterial;\n\nMeshStandardMaterial.prototype.isMeshStandardMaterial = true;\n\nMeshStandardMaterial.prototype.copy = function ( source ) {\n\n\tMaterial.prototype.copy.call( this, source );\n\n\tthis.defines = { 'STANDARD': '' };\n\n\tthis.color.copy( source.color );\n\tthis.roughness = source.roughness;\n\tthis.metalness = source.metalness;\n\n\tthis.map = source.map;\n\n\tthis.lightMap = source.lightMap;\n\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\tthis.aoMap = source.aoMap;\n\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\tthis.emissive.copy( source.emissive );\n\tthis.emissiveMap = source.emissiveMap;\n\tthis.emissiveIntensity = source.emissiveIntensity;\n\n\tthis.bumpMap = source.bumpMap;\n\tthis.bumpScale = source.bumpScale;\n\n\tthis.normalMap = source.normalMap;\n\tthis.normalScale.copy( source.normalScale );\n\n\tthis.displacementMap = source.displacementMap;\n\tthis.displacementScale = source.displacementScale;\n\tthis.displacementBias = source.displacementBias;\n\n\tthis.roughnessMap = source.roughnessMap;\n\n\tthis.metalnessMap = source.metalnessMap;\n\n\tthis.alphaMap = source.alphaMap;\n\n\tthis.envMap = source.envMap;\n\tthis.envMapIntensity = source.envMapIntensity;\n\n\tthis.refractionRatio = source.refractionRatio;\n\n\tthis.wireframe = source.wireframe;\n\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\tthis.wireframeLinecap = source.wireframeLinecap;\n\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\tthis.skinning = source.skinning;\n\tthis.morphTargets = source.morphTargets;\n\tthis.morphNormals = source.morphNormals;\n\n\treturn this;\n\n};\n\n/**\n * @author WestLangley / http://github.com/WestLangley\n *\n * parameters = {\n * reflectivity: \n * }\n */\n\nfunction MeshPhysicalMaterial( parameters ) {\n\n\tMeshStandardMaterial.call( this );\n\n\tthis.defines = { 'PHYSICAL': '' };\n\n\tthis.type = 'MeshPhysicalMaterial';\n\n\tthis.reflectivity = 0.5; // maps to F0 = 0.04\n\n\tthis.clearCoat = 0.0;\n\tthis.clearCoatRoughness = 0.0;\n\n\tthis.setValues( parameters );\n\n}\n\nMeshPhysicalMaterial.prototype = Object.create( MeshStandardMaterial.prototype );\nMeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial;\n\nMeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true;\n\nMeshPhysicalMaterial.prototype.copy = function ( source ) {\n\n\tMeshStandardMaterial.prototype.copy.call( this, source );\n\n\tthis.defines = { 'PHYSICAL': '' };\n\n\tthis.reflectivity = source.reflectivity;\n\n\tthis.clearCoat = source.clearCoat;\n\tthis.clearCoatRoughness = source.clearCoatRoughness;\n\n\treturn this;\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author alteredq / http://alteredqualia.com/\n *\n * parameters = {\n * color: ,\n * specular: ,\n * shininess: ,\n * opacity: ,\n *\n * map: new THREE.Texture( ),\n *\n * lightMap: new THREE.Texture( ),\n * lightMapIntensity: \n *\n * aoMap: new THREE.Texture( ),\n * aoMapIntensity: \n *\n * emissive: ,\n * emissiveIntensity: \n * emissiveMap: new THREE.Texture( ),\n *\n * bumpMap: new THREE.Texture( ),\n * bumpScale: ,\n *\n * normalMap: new THREE.Texture( ),\n * normalScale: ,\n *\n * displacementMap: new THREE.Texture( ),\n * displacementScale: ,\n * displacementBias: ,\n *\n * specularMap: new THREE.Texture( ),\n *\n * alphaMap: new THREE.Texture( ),\n *\n * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),\n * combine: THREE.Multiply,\n * reflectivity: ,\n * refractionRatio: ,\n *\n * wireframe: ,\n * wireframeLinewidth: ,\n *\n * skinning: ,\n * morphTargets: ,\n * morphNormals: \n * }\n */\n\nfunction MeshPhongMaterial( parameters ) {\n\n\tMaterial.call( this );\n\n\tthis.type = 'MeshPhongMaterial';\n\n\tthis.color = new Color( 0xffffff ); // diffuse\n\tthis.specular = new Color( 0x111111 );\n\tthis.shininess = 30;\n\n\tthis.map = null;\n\n\tthis.lightMap = null;\n\tthis.lightMapIntensity = 1.0;\n\n\tthis.aoMap = null;\n\tthis.aoMapIntensity = 1.0;\n\n\tthis.emissive = new Color( 0x000000 );\n\tthis.emissiveIntensity = 1.0;\n\tthis.emissiveMap = null;\n\n\tthis.bumpMap = null;\n\tthis.bumpScale = 1;\n\n\tthis.normalMap = null;\n\tthis.normalScale = new Vector2( 1, 1 );\n\n\tthis.displacementMap = null;\n\tthis.displacementScale = 1;\n\tthis.displacementBias = 0;\n\n\tthis.specularMap = null;\n\n\tthis.alphaMap = null;\n\n\tthis.envMap = null;\n\tthis.combine = MultiplyOperation;\n\tthis.reflectivity = 1;\n\tthis.refractionRatio = 0.98;\n\n\tthis.wireframe = false;\n\tthis.wireframeLinewidth = 1;\n\tthis.wireframeLinecap = 'round';\n\tthis.wireframeLinejoin = 'round';\n\n\tthis.skinning = false;\n\tthis.morphTargets = false;\n\tthis.morphNormals = false;\n\n\tthis.setValues( parameters );\n\n}\n\nMeshPhongMaterial.prototype = Object.create( Material.prototype );\nMeshPhongMaterial.prototype.constructor = MeshPhongMaterial;\n\nMeshPhongMaterial.prototype.isMeshPhongMaterial = true;\n\nMeshPhongMaterial.prototype.copy = function ( source ) {\n\n\tMaterial.prototype.copy.call( this, source );\n\n\tthis.color.copy( source.color );\n\tthis.specular.copy( source.specular );\n\tthis.shininess = source.shininess;\n\n\tthis.map = source.map;\n\n\tthis.lightMap = source.lightMap;\n\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\tthis.aoMap = source.aoMap;\n\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\tthis.emissive.copy( source.emissive );\n\tthis.emissiveMap = source.emissiveMap;\n\tthis.emissiveIntensity = source.emissiveIntensity;\n\n\tthis.bumpMap = source.bumpMap;\n\tthis.bumpScale = source.bumpScale;\n\n\tthis.normalMap = source.normalMap;\n\tthis.normalScale.copy( source.normalScale );\n\n\tthis.displacementMap = source.displacementMap;\n\tthis.displacementScale = source.displacementScale;\n\tthis.displacementBias = source.displacementBias;\n\n\tthis.specularMap = source.specularMap;\n\n\tthis.alphaMap = source.alphaMap;\n\n\tthis.envMap = source.envMap;\n\tthis.combine = source.combine;\n\tthis.reflectivity = source.reflectivity;\n\tthis.refractionRatio = source.refractionRatio;\n\n\tthis.wireframe = source.wireframe;\n\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\tthis.wireframeLinecap = source.wireframeLinecap;\n\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\tthis.skinning = source.skinning;\n\tthis.morphTargets = source.morphTargets;\n\tthis.morphNormals = source.morphNormals;\n\n\treturn this;\n\n};\n\n/**\n * @author takahirox / http://github.com/takahirox\n *\n * parameters = {\n * gradientMap: new THREE.Texture( )\n * }\n */\n\nfunction MeshToonMaterial( parameters ) {\n\n\tMeshPhongMaterial.call( this );\n\n\tthis.defines = { 'TOON': '' };\n\n\tthis.type = 'MeshToonMaterial';\n\n\tthis.gradientMap = null;\n\n\tthis.setValues( parameters );\n\n}\n\nMeshToonMaterial.prototype = Object.create( MeshPhongMaterial.prototype );\nMeshToonMaterial.prototype.constructor = MeshToonMaterial;\n\nMeshToonMaterial.prototype.isMeshToonMaterial = true;\n\nMeshToonMaterial.prototype.copy = function ( source ) {\n\n\tMeshPhongMaterial.prototype.copy.call( this, source );\n\n\tthis.gradientMap = source.gradientMap;\n\n\treturn this;\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author WestLangley / http://github.com/WestLangley\n *\n * parameters = {\n * opacity: ,\n *\n * bumpMap: new THREE.Texture( ),\n * bumpScale: ,\n *\n * normalMap: new THREE.Texture( ),\n * normalScale: ,\n *\n * displacementMap: new THREE.Texture( ),\n * displacementScale: ,\n * displacementBias: ,\n *\n * wireframe: ,\n * wireframeLinewidth: \n *\n * skinning: ,\n * morphTargets: ,\n * morphNormals: \n * }\n */\n\nfunction MeshNormalMaterial( parameters ) {\n\n\tMaterial.call( this, parameters );\n\n\tthis.type = 'MeshNormalMaterial';\n\n\tthis.bumpMap = null;\n\tthis.bumpScale = 1;\n\n\tthis.normalMap = null;\n\tthis.normalScale = new Vector2( 1, 1 );\n\n\tthis.displacementMap = null;\n\tthis.displacementScale = 1;\n\tthis.displacementBias = 0;\n\n\tthis.wireframe = false;\n\tthis.wireframeLinewidth = 1;\n\n\tthis.fog = false;\n\tthis.lights = false;\n\n\tthis.skinning = false;\n\tthis.morphTargets = false;\n\tthis.morphNormals = false;\n\n\tthis.setValues( parameters );\n\n}\n\nMeshNormalMaterial.prototype = Object.create( Material.prototype );\nMeshNormalMaterial.prototype.constructor = MeshNormalMaterial;\n\nMeshNormalMaterial.prototype.isMeshNormalMaterial = true;\n\nMeshNormalMaterial.prototype.copy = function ( source ) {\n\n\tMaterial.prototype.copy.call( this, source );\n\n\tthis.bumpMap = source.bumpMap;\n\tthis.bumpScale = source.bumpScale;\n\n\tthis.normalMap = source.normalMap;\n\tthis.normalScale.copy( source.normalScale );\n\n\tthis.displacementMap = source.displacementMap;\n\tthis.displacementScale = source.displacementScale;\n\tthis.displacementBias = source.displacementBias;\n\n\tthis.wireframe = source.wireframe;\n\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\n\tthis.skinning = source.skinning;\n\tthis.morphTargets = source.morphTargets;\n\tthis.morphNormals = source.morphNormals;\n\n\treturn this;\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author alteredq / http://alteredqualia.com/\n *\n * parameters = {\n * color: ,\n * opacity: ,\n *\n * map: new THREE.Texture( ),\n *\n * lightMap: new THREE.Texture( ),\n * lightMapIntensity: \n *\n * aoMap: new THREE.Texture( ),\n * aoMapIntensity: \n *\n * emissive: ,\n * emissiveIntensity: \n * emissiveMap: new THREE.Texture( ),\n *\n * specularMap: new THREE.Texture( ),\n *\n * alphaMap: new THREE.Texture( ),\n *\n * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),\n * combine: THREE.Multiply,\n * reflectivity: ,\n * refractionRatio: ,\n *\n * wireframe: ,\n * wireframeLinewidth: ,\n *\n * skinning: ,\n * morphTargets: ,\n * morphNormals: \n * }\n */\n\nfunction MeshLambertMaterial( parameters ) {\n\n\tMaterial.call( this );\n\n\tthis.type = 'MeshLambertMaterial';\n\n\tthis.color = new Color( 0xffffff ); // diffuse\n\n\tthis.map = null;\n\n\tthis.lightMap = null;\n\tthis.lightMapIntensity = 1.0;\n\n\tthis.aoMap = null;\n\tthis.aoMapIntensity = 1.0;\n\n\tthis.emissive = new Color( 0x000000 );\n\tthis.emissiveIntensity = 1.0;\n\tthis.emissiveMap = null;\n\n\tthis.specularMap = null;\n\n\tthis.alphaMap = null;\n\n\tthis.envMap = null;\n\tthis.combine = MultiplyOperation;\n\tthis.reflectivity = 1;\n\tthis.refractionRatio = 0.98;\n\n\tthis.wireframe = false;\n\tthis.wireframeLinewidth = 1;\n\tthis.wireframeLinecap = 'round';\n\tthis.wireframeLinejoin = 'round';\n\n\tthis.skinning = false;\n\tthis.morphTargets = false;\n\tthis.morphNormals = false;\n\n\tthis.setValues( parameters );\n\n}\n\nMeshLambertMaterial.prototype = Object.create( Material.prototype );\nMeshLambertMaterial.prototype.constructor = MeshLambertMaterial;\n\nMeshLambertMaterial.prototype.isMeshLambertMaterial = true;\n\nMeshLambertMaterial.prototype.copy = function ( source ) {\n\n\tMaterial.prototype.copy.call( this, source );\n\n\tthis.color.copy( source.color );\n\n\tthis.map = source.map;\n\n\tthis.lightMap = source.lightMap;\n\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\tthis.aoMap = source.aoMap;\n\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\tthis.emissive.copy( source.emissive );\n\tthis.emissiveMap = source.emissiveMap;\n\tthis.emissiveIntensity = source.emissiveIntensity;\n\n\tthis.specularMap = source.specularMap;\n\n\tthis.alphaMap = source.alphaMap;\n\n\tthis.envMap = source.envMap;\n\tthis.combine = source.combine;\n\tthis.reflectivity = source.reflectivity;\n\tthis.refractionRatio = source.refractionRatio;\n\n\tthis.wireframe = source.wireframe;\n\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\tthis.wireframeLinecap = source.wireframeLinecap;\n\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\tthis.skinning = source.skinning;\n\tthis.morphTargets = source.morphTargets;\n\tthis.morphNormals = source.morphNormals;\n\n\treturn this;\n\n};\n\n/**\n * @author alteredq / http://alteredqualia.com/\n *\n * parameters = {\n * color: ,\n * opacity: ,\n *\n * linewidth: ,\n *\n * scale: ,\n * dashSize: ,\n * gapSize: \n * }\n */\n\nfunction LineDashedMaterial( parameters ) {\n\n\tMaterial.call( this );\n\n\tthis.type = 'LineDashedMaterial';\n\n\tthis.color = new Color( 0xffffff );\n\n\tthis.linewidth = 1;\n\n\tthis.scale = 1;\n\tthis.dashSize = 3;\n\tthis.gapSize = 1;\n\n\tthis.lights = false;\n\n\tthis.setValues( parameters );\n\n}\n\nLineDashedMaterial.prototype = Object.create( Material.prototype );\nLineDashedMaterial.prototype.constructor = LineDashedMaterial;\n\nLineDashedMaterial.prototype.isLineDashedMaterial = true;\n\nLineDashedMaterial.prototype.copy = function ( source ) {\n\n\tMaterial.prototype.copy.call( this, source );\n\n\tthis.color.copy( source.color );\n\n\tthis.linewidth = source.linewidth;\n\n\tthis.scale = source.scale;\n\tthis.dashSize = source.dashSize;\n\tthis.gapSize = source.gapSize;\n\n\treturn this;\n\n};\n\n\n\nvar Materials = Object.freeze({\n\tShadowMaterial: ShadowMaterial,\n\tSpriteMaterial: SpriteMaterial,\n\tRawShaderMaterial: RawShaderMaterial,\n\tShaderMaterial: ShaderMaterial,\n\tPointsMaterial: PointsMaterial,\n\tMultiMaterial: MultiMaterial,\n\tMeshPhysicalMaterial: MeshPhysicalMaterial,\n\tMeshStandardMaterial: MeshStandardMaterial,\n\tMeshPhongMaterial: MeshPhongMaterial,\n\tMeshToonMaterial: MeshToonMaterial,\n\tMeshNormalMaterial: MeshNormalMaterial,\n\tMeshLambertMaterial: MeshLambertMaterial,\n\tMeshDepthMaterial: MeshDepthMaterial,\n\tMeshBasicMaterial: MeshBasicMaterial,\n\tLineDashedMaterial: LineDashedMaterial,\n\tLineBasicMaterial: LineBasicMaterial,\n\tMaterial: Material\n});\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nvar Cache = {\n\n\tenabled: false,\n\n\tfiles: {},\n\n\tadd: function ( key, file ) {\n\n\t\tif ( this.enabled === false ) return;\n\n\t\t// console.log( 'THREE.Cache', 'Adding key:', key );\n\n\t\tthis.files[ key ] = file;\n\n\t},\n\n\tget: function ( key ) {\n\n\t\tif ( this.enabled === false ) return;\n\n\t\t// console.log( 'THREE.Cache', 'Checking key:', key );\n\n\t\treturn this.files[ key ];\n\n\t},\n\n\tremove: function ( key ) {\n\n\t\tdelete this.files[ key ];\n\n\t},\n\n\tclear: function () {\n\n\t\tthis.files = {};\n\n\t}\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction LoadingManager( onLoad, onProgress, onError ) {\n\n\tvar scope = this;\n\n\tvar isLoading = false, itemsLoaded = 0, itemsTotal = 0;\n\n\tthis.onStart = undefined;\n\tthis.onLoad = onLoad;\n\tthis.onProgress = onProgress;\n\tthis.onError = onError;\n\n\tthis.itemStart = function ( url ) {\n\n\t\titemsTotal ++;\n\n\t\tif ( isLoading === false ) {\n\n\t\t\tif ( scope.onStart !== undefined ) {\n\n\t\t\t\tscope.onStart( url, itemsLoaded, itemsTotal );\n\n\t\t\t}\n\n\t\t}\n\n\t\tisLoading = true;\n\n\t};\n\n\tthis.itemEnd = function ( url ) {\n\n\t\titemsLoaded ++;\n\n\t\tif ( scope.onProgress !== undefined ) {\n\n\t\t\tscope.onProgress( url, itemsLoaded, itemsTotal );\n\n\t\t}\n\n\t\tif ( itemsLoaded === itemsTotal ) {\n\n\t\t\tisLoading = false;\n\n\t\t\tif ( scope.onLoad !== undefined ) {\n\n\t\t\t\tscope.onLoad();\n\n\t\t\t}\n\n\t\t}\n\n\t};\n\n\tthis.itemError = function ( url ) {\n\n\t\tif ( scope.onError !== undefined ) {\n\n\t\t\tscope.onError( url );\n\n\t\t}\n\n\t};\n\n}\n\nvar DefaultLoadingManager = new LoadingManager();\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction FileLoader( manager ) {\n\n\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n}\n\nObject.assign( FileLoader.prototype, {\n\n\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\tif ( url === undefined ) url = '';\n\n\t\tif ( this.path !== undefined ) url = this.path + url;\n\n\t\tvar scope = this;\n\n\t\tvar cached = Cache.get( url );\n\n\t\tif ( cached !== undefined ) {\n\n\t\t\tscope.manager.itemStart( url );\n\n\t\t\tsetTimeout( function () {\n\n\t\t\t\tif ( onLoad ) onLoad( cached );\n\n\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t}, 0 );\n\n\t\t\treturn cached;\n\n\t\t}\n\n\t\t// Check for data: URI\n\t\tvar dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;\n\t\tvar dataUriRegexResult = url.match( dataUriRegex );\n\n\t\t// Safari can not handle Data URIs through XMLHttpRequest so process manually\n\t\tif ( dataUriRegexResult ) {\n\n\t\t\tvar mimeType = dataUriRegexResult[ 1 ];\n\t\t\tvar isBase64 = !! dataUriRegexResult[ 2 ];\n\t\t\tvar data = dataUriRegexResult[ 3 ];\n\n\t\t\tdata = window.decodeURIComponent( data );\n\n\t\t\tif ( isBase64 ) data = window.atob( data );\n\n\t\t\ttry {\n\n\t\t\t\tvar response;\n\t\t\t\tvar responseType = ( this.responseType || '' ).toLowerCase();\n\n\t\t\t\tswitch ( responseType ) {\n\n\t\t\t\t\tcase 'arraybuffer':\n\t\t\t\t\tcase 'blob':\n\n\t\t\t\t\t \tresponse = new ArrayBuffer( data.length );\n\n\t\t\t\t\t\tvar view = new Uint8Array( response );\n\n\t\t\t\t\t\tfor ( var i = 0; i < data.length; i ++ ) {\n\n\t\t\t\t\t\t\tview[ i ] = data.charCodeAt( i );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( responseType === 'blob' ) {\n\n\t\t\t\t\t\t\tresponse = new Blob( [ response ], { type: mimeType } );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'document':\n\n\t\t\t\t\t\tvar parser = new DOMParser();\n\t\t\t\t\t\tresponse = parser.parseFromString( data, mimeType );\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'json':\n\n\t\t\t\t\t\tresponse = JSON.parse( data );\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault: // 'text' or other\n\n\t\t\t\t\t\tresponse = data;\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t\t// Wait for next browser tick\n\t\t\t\twindow.setTimeout( function () {\n\n\t\t\t\t\tif ( onLoad ) onLoad( response );\n\n\t\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t\t}, 0 );\n\n\t\t\t} catch ( error ) {\n\n\t\t\t\t// Wait for next browser tick\n\t\t\t\twindow.setTimeout( function () {\n\n\t\t\t\t\tif ( onError ) onError( error );\n\n\t\t\t\t\tscope.manager.itemError( url );\n\n\t\t\t\t}, 0 );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tvar request = new XMLHttpRequest();\n\t\t\trequest.open( 'GET', url, true );\n\n\t\t\trequest.addEventListener( 'load', function ( event ) {\n\n\t\t\t\tvar response = event.target.response;\n\n\t\t\t\tCache.add( url, response );\n\n\t\t\t\tif ( this.status === 200 ) {\n\n\t\t\t\t\tif ( onLoad ) onLoad( response );\n\n\t\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t\t} else if ( this.status === 0 ) {\n\n\t\t\t\t\t// Some browsers return HTTP Status 0 when using non-http protocol\n\t\t\t\t\t// e.g. 'file://' or 'data://'. Handle as success.\n\n\t\t\t\t\tconsole.warn( 'THREE.FileLoader: HTTP Status 0 received.' );\n\n\t\t\t\t\tif ( onLoad ) onLoad( response );\n\n\t\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( onError ) onError( event );\n\n\t\t\t\t\tscope.manager.itemError( url );\n\n\t\t\t\t}\n\n\t\t\t}, false );\n\n\t\t\tif ( onProgress !== undefined ) {\n\n\t\t\t\trequest.addEventListener( 'progress', function ( event ) {\n\n\t\t\t\t\tonProgress( event );\n\n\t\t\t\t}, false );\n\n\t\t\t}\n\n\t\t\trequest.addEventListener( 'error', function ( event ) {\n\n\t\t\t\tif ( onError ) onError( event );\n\n\t\t\t\tscope.manager.itemError( url );\n\n\t\t\t}, false );\n\n\t\t\tif ( this.responseType !== undefined ) request.responseType = this.responseType;\n\t\t\tif ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;\n\n\t\t\tif ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' );\n\n\t\t\trequest.send( null );\n\n\t\t}\n\n\t\tscope.manager.itemStart( url );\n\n\t\treturn request;\n\n\t},\n\n\tsetPath: function ( value ) {\n\n\t\tthis.path = value;\n\t\treturn this;\n\n\t},\n\n\tsetResponseType: function ( value ) {\n\n\t\tthis.responseType = value;\n\t\treturn this;\n\n\t},\n\n\tsetWithCredentials: function ( value ) {\n\n\t\tthis.withCredentials = value;\n\t\treturn this;\n\n\t},\n\n\tsetMimeType: function ( value ) {\n\n\t\tthis.mimeType = value;\n\t\treturn this;\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n *\n * Abstract Base class to block based textures loader (dds, pvr, ...)\n */\n\nfunction CompressedTextureLoader( manager ) {\n\n\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n\t// override in sub classes\n\tthis._parser = null;\n\n}\n\nObject.assign( CompressedTextureLoader.prototype, {\n\n\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\tvar scope = this;\n\n\t\tvar images = [];\n\n\t\tvar texture = new CompressedTexture();\n\t\ttexture.image = images;\n\n\t\tvar loader = new FileLoader( this.manager );\n\t\tloader.setPath( this.path );\n\t\tloader.setResponseType( 'arraybuffer' );\n\n\t\tfunction loadTexture( i ) {\n\n\t\t\tloader.load( url[ i ], function ( buffer ) {\n\n\t\t\t\tvar texDatas = scope._parser( buffer, true );\n\n\t\t\t\timages[ i ] = {\n\t\t\t\t\twidth: texDatas.width,\n\t\t\t\t\theight: texDatas.height,\n\t\t\t\t\tformat: texDatas.format,\n\t\t\t\t\tmipmaps: texDatas.mipmaps\n\t\t\t\t};\n\n\t\t\t\tloaded += 1;\n\n\t\t\t\tif ( loaded === 6 ) {\n\n\t\t\t\t\tif ( texDatas.mipmapCount === 1 )\n\t\t\t\t\t\ttexture.minFilter = LinearFilter;\n\n\t\t\t\t\ttexture.format = texDatas.format;\n\t\t\t\t\ttexture.needsUpdate = true;\n\n\t\t\t\t\tif ( onLoad ) onLoad( texture );\n\n\t\t\t\t}\n\n\t\t\t}, onProgress, onError );\n\n\t\t}\n\n\t\tif ( Array.isArray( url ) ) {\n\n\t\t\tvar loaded = 0;\n\n\t\t\tfor ( var i = 0, il = url.length; i < il; ++ i ) {\n\n\t\t\t\tloadTexture( i );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// compressed cubemap texture stored in a single DDS file\n\n\t\t\tloader.load( url, function ( buffer ) {\n\n\t\t\t\tvar texDatas = scope._parser( buffer, true );\n\n\t\t\t\tif ( texDatas.isCubemap ) {\n\n\t\t\t\t\tvar faces = texDatas.mipmaps.length / texDatas.mipmapCount;\n\n\t\t\t\t\tfor ( var f = 0; f < faces; f ++ ) {\n\n\t\t\t\t\t\timages[ f ] = { mipmaps : [] };\n\n\t\t\t\t\t\tfor ( var i = 0; i < texDatas.mipmapCount; i ++ ) {\n\n\t\t\t\t\t\t\timages[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] );\n\t\t\t\t\t\t\timages[ f ].format = texDatas.format;\n\t\t\t\t\t\t\timages[ f ].width = texDatas.width;\n\t\t\t\t\t\t\timages[ f ].height = texDatas.height;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\ttexture.image.width = texDatas.width;\n\t\t\t\t\ttexture.image.height = texDatas.height;\n\t\t\t\t\ttexture.mipmaps = texDatas.mipmaps;\n\n\t\t\t\t}\n\n\t\t\t\tif ( texDatas.mipmapCount === 1 ) {\n\n\t\t\t\t\ttexture.minFilter = LinearFilter;\n\n\t\t\t\t}\n\n\t\t\t\ttexture.format = texDatas.format;\n\t\t\t\ttexture.needsUpdate = true;\n\n\t\t\t\tif ( onLoad ) onLoad( texture );\n\n\t\t\t}, onProgress, onError );\n\n\t\t}\n\n\t\treturn texture;\n\n\t},\n\n\tsetPath: function ( value ) {\n\n\t\tthis.path = value;\n\t\treturn this;\n\n\t}\n\n} );\n\n/**\n * @author Nikos M. / https://github.com/foo123/\n *\n * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)\n */\n\nfunction DataTextureLoader( manager ) {\n\n\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n\t// override in sub classes\n\tthis._parser = null;\n\n}\n\nObject.assign( DataTextureLoader.prototype, {\n\n\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\tvar scope = this;\n\n\t\tvar texture = new DataTexture();\n\n\t\tvar loader = new FileLoader( this.manager );\n\t\tloader.setResponseType( 'arraybuffer' );\n\n\t\tloader.load( url, function ( buffer ) {\n\n\t\t\tvar texData = scope._parser( buffer );\n\n\t\t\tif ( ! texData ) return;\n\n\t\t\tif ( undefined !== texData.image ) {\n\n\t\t\t\ttexture.image = texData.image;\n\n\t\t\t} else if ( undefined !== texData.data ) {\n\n\t\t\t\ttexture.image.width = texData.width;\n\t\t\t\ttexture.image.height = texData.height;\n\t\t\t\ttexture.image.data = texData.data;\n\n\t\t\t}\n\n\t\t\ttexture.wrapS = undefined !== texData.wrapS ? texData.wrapS : ClampToEdgeWrapping;\n\t\t\ttexture.wrapT = undefined !== texData.wrapT ? texData.wrapT : ClampToEdgeWrapping;\n\n\t\t\ttexture.magFilter = undefined !== texData.magFilter ? texData.magFilter : LinearFilter;\n\t\t\ttexture.minFilter = undefined !== texData.minFilter ? texData.minFilter : LinearMipMapLinearFilter;\n\n\t\t\ttexture.anisotropy = undefined !== texData.anisotropy ? texData.anisotropy : 1;\n\n\t\t\tif ( undefined !== texData.format ) {\n\n\t\t\t\ttexture.format = texData.format;\n\n\t\t\t}\n\t\t\tif ( undefined !== texData.type ) {\n\n\t\t\t\ttexture.type = texData.type;\n\n\t\t\t}\n\n\t\t\tif ( undefined !== texData.mipmaps ) {\n\n\t\t\t\ttexture.mipmaps = texData.mipmaps;\n\n\t\t\t}\n\n\t\t\tif ( 1 === texData.mipmapCount ) {\n\n\t\t\t\ttexture.minFilter = LinearFilter;\n\n\t\t\t}\n\n\t\t\ttexture.needsUpdate = true;\n\n\t\t\tif ( onLoad ) onLoad( texture, texData );\n\n\t\t}, onProgress, onError );\n\n\n\t\treturn texture;\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction ImageLoader( manager ) {\n\n\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n}\n\nObject.assign( ImageLoader.prototype, {\n\n\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\tif ( url === undefined ) url = '';\n\n\t\tif ( this.path !== undefined ) url = this.path + url;\n\n\t\tvar scope = this;\n\n\t\tvar cached = Cache.get( url );\n\n\t\tif ( cached !== undefined ) {\n\n\t\t\tscope.manager.itemStart( url );\n\n\t\t\tsetTimeout( function () {\n\n\t\t\t\tif ( onLoad ) onLoad( cached );\n\n\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t}, 0 );\n\n\t\t\treturn cached;\n\n\t\t}\n\n\t\tvar image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' );\n\n\t\timage.addEventListener( 'load', function () {\n\n\t\t\tCache.add( url, this );\n\n\t\t\tif ( onLoad ) onLoad( this );\n\n\t\t\tscope.manager.itemEnd( url );\n\n\t\t}, false );\n\n\t\t/*\n\t\timage.addEventListener( 'progress', function ( event ) {\n\n\t\t\tif ( onProgress ) onProgress( event );\n\n\t\t}, false );\n\t\t*/\n\n\t\timage.addEventListener( 'error', function ( event ) {\n\n\t\t\tif ( onError ) onError( event );\n\n\t\t\tscope.manager.itemError( url );\n\n\t\t}, false );\n\n\t\tif ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;\n\n\t\tscope.manager.itemStart( url );\n\n\t\timage.src = url;\n\n\t\treturn image;\n\n\t},\n\n\tsetCrossOrigin: function ( value ) {\n\n\t\tthis.crossOrigin = value;\n\t\treturn this;\n\n\t},\n\n\tsetPath: function ( value ) {\n\n\t\tthis.path = value;\n\t\treturn this;\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction CubeTextureLoader( manager ) {\n\n\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n}\n\nObject.assign( CubeTextureLoader.prototype, {\n\n\tload: function ( urls, onLoad, onProgress, onError ) {\n\n\t\tvar texture = new CubeTexture();\n\n\t\tvar loader = new ImageLoader( this.manager );\n\t\tloader.setCrossOrigin( this.crossOrigin );\n\t\tloader.setPath( this.path );\n\n\t\tvar loaded = 0;\n\n\t\tfunction loadTexture( i ) {\n\n\t\t\tloader.load( urls[ i ], function ( image ) {\n\n\t\t\t\ttexture.images[ i ] = image;\n\n\t\t\t\tloaded ++;\n\n\t\t\t\tif ( loaded === 6 ) {\n\n\t\t\t\t\ttexture.needsUpdate = true;\n\n\t\t\t\t\tif ( onLoad ) onLoad( texture );\n\n\t\t\t\t}\n\n\t\t\t}, undefined, onError );\n\n\t\t}\n\n\t\tfor ( var i = 0; i < urls.length; ++ i ) {\n\n\t\t\tloadTexture( i );\n\n\t\t}\n\n\t\treturn texture;\n\n\t},\n\n\tsetCrossOrigin: function ( value ) {\n\n\t\tthis.crossOrigin = value;\n\t\treturn this;\n\n\t},\n\n\tsetPath: function ( value ) {\n\n\t\tthis.path = value;\n\t\treturn this;\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction TextureLoader( manager ) {\n\n\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n}\n\nObject.assign( TextureLoader.prototype, {\n\n\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\tvar texture = new Texture();\n\n\t\tvar loader = new ImageLoader( this.manager );\n\t\tloader.setCrossOrigin( this.crossOrigin );\n\t\tloader.setPath( this.path );\n\t\tloader.load( url, function ( image ) {\n\n\t\t\t// JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB.\n\t\t\tvar isJPEG = url.search( /\\.(jpg|jpeg)$/ ) > 0 || url.search( /^data\\:image\\/jpeg/ ) === 0;\n\n\t\t\ttexture.format = isJPEG ? RGBFormat : RGBAFormat;\n\t\t\ttexture.image = image;\n\t\t\ttexture.needsUpdate = true;\n\n\t\t\tif ( onLoad !== undefined ) {\n\n\t\t\t\tonLoad( texture );\n\n\t\t\t}\n\n\t\t}, onProgress, onError );\n\n\t\treturn texture;\n\n\t},\n\n\tsetCrossOrigin: function ( value ) {\n\n\t\tthis.crossOrigin = value;\n\t\treturn this;\n\n\t},\n\n\tsetPath: function ( value ) {\n\n\t\tthis.path = value;\n\t\treturn this;\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction Light( color, intensity ) {\n\n\tObject3D.call( this );\n\n\tthis.type = 'Light';\n\n\tthis.color = new Color( color );\n\tthis.intensity = intensity !== undefined ? intensity : 1;\n\n\tthis.receiveShadow = undefined;\n\n}\n\nLight.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\tconstructor: Light,\n\n\tisLight: true,\n\n\tcopy: function ( source ) {\n\n\t\tObject3D.prototype.copy.call( this, source );\n\n\t\tthis.color.copy( source.color );\n\t\tthis.intensity = source.intensity;\n\n\t\treturn this;\n\n\t},\n\n\ttoJSON: function ( meta ) {\n\n\t\tvar data = Object3D.prototype.toJSON.call( this, meta );\n\n\t\tdata.object.color = this.color.getHex();\n\t\tdata.object.intensity = this.intensity;\n\n\t\tif ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex();\n\n\t\tif ( this.distance !== undefined ) data.object.distance = this.distance;\n\t\tif ( this.angle !== undefined ) data.object.angle = this.angle;\n\t\tif ( this.decay !== undefined ) data.object.decay = this.decay;\n\t\tif ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra;\n\n\t\tif ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON();\n\n\t\treturn data;\n\n\t}\n\n} );\n\n/**\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction HemisphereLight( skyColor, groundColor, intensity ) {\n\n\tLight.call( this, skyColor, intensity );\n\n\tthis.type = 'HemisphereLight';\n\n\tthis.castShadow = undefined;\n\n\tthis.position.copy( Object3D.DefaultUp );\n\tthis.updateMatrix();\n\n\tthis.groundColor = new Color( groundColor );\n\n}\n\nHemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), {\n\n\tconstructor: HemisphereLight,\n\n\tisHemisphereLight: true,\n\n\tcopy: function ( source ) {\n\n\t\tLight.prototype.copy.call( this, source );\n\n\t\tthis.groundColor.copy( source.groundColor );\n\n\t\treturn this;\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction LightShadow( camera ) {\n\n\tthis.camera = camera;\n\n\tthis.bias = 0;\n\tthis.radius = 1;\n\n\tthis.mapSize = new Vector2( 512, 512 );\n\n\tthis.map = null;\n\tthis.matrix = new Matrix4();\n\n}\n\nObject.assign( LightShadow.prototype, {\n\n\tcopy: function ( source ) {\n\n\t\tthis.camera = source.camera.clone();\n\n\t\tthis.bias = source.bias;\n\t\tthis.radius = source.radius;\n\n\t\tthis.mapSize.copy( source.mapSize );\n\n\t\treturn this;\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor().copy( this );\n\n\t},\n\n\ttoJSON: function () {\n\n\t\tvar object = {};\n\n\t\tif ( this.bias !== 0 ) object.bias = this.bias;\n\t\tif ( this.radius !== 1 ) object.radius = this.radius;\n\t\tif ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray();\n\n\t\tobject.camera = this.camera.toJSON( false ).object;\n\t\tdelete object.camera.matrix;\n\n\t\treturn object;\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction SpotLightShadow() {\n\n\tLightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) );\n\n}\n\nSpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {\n\n\tconstructor: SpotLightShadow,\n\n\tisSpotLightShadow: true,\n\n\tupdate: function ( light ) {\n\n\t\tvar fov = _Math.RAD2DEG * 2 * light.angle;\n\t\tvar aspect = this.mapSize.width / this.mapSize.height;\n\t\tvar far = light.distance || 500;\n\n\t\tvar camera = this.camera;\n\n\t\tif ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {\n\n\t\t\tcamera.fov = fov;\n\t\t\tcamera.aspect = aspect;\n\t\t\tcamera.far = far;\n\t\t\tcamera.updateProjectionMatrix();\n\n\t\t}\n\n\t}\n\n} );\n\n/**\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction SpotLight( color, intensity, distance, angle, penumbra, decay ) {\n\n\tLight.call( this, color, intensity );\n\n\tthis.type = 'SpotLight';\n\n\tthis.position.copy( Object3D.DefaultUp );\n\tthis.updateMatrix();\n\n\tthis.target = new Object3D();\n\n\tObject.defineProperty( this, 'power', {\n\t\tget: function () {\n\t\t\t// intensity = power per solid angle.\n\t\t\t// ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf\n\t\t\treturn this.intensity * Math.PI;\n\t\t},\n\t\tset: function ( power ) {\n\t\t\t// intensity = power per solid angle.\n\t\t\t// ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf\n\t\t\tthis.intensity = power / Math.PI;\n\t\t}\n\t} );\n\n\tthis.distance = ( distance !== undefined ) ? distance : 0;\n\tthis.angle = ( angle !== undefined ) ? angle : Math.PI / 3;\n\tthis.penumbra = ( penumbra !== undefined ) ? penumbra : 0;\n\tthis.decay = ( decay !== undefined ) ? decay : 1;\t// for physically correct lights, should be 2.\n\n\tthis.shadow = new SpotLightShadow();\n\n}\n\nSpotLight.prototype = Object.assign( Object.create( Light.prototype ), {\n\n\tconstructor: SpotLight,\n\n\tisSpotLight: true,\n\n\tcopy: function ( source ) {\n\n\t\tLight.prototype.copy.call( this, source );\n\n\t\tthis.distance = source.distance;\n\t\tthis.angle = source.angle;\n\t\tthis.penumbra = source.penumbra;\n\t\tthis.decay = source.decay;\n\n\t\tthis.target = source.target.clone();\n\n\t\tthis.shadow = source.shadow.clone();\n\n\t\treturn this;\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\n\nfunction PointLight( color, intensity, distance, decay ) {\n\n\tLight.call( this, color, intensity );\n\n\tthis.type = 'PointLight';\n\n\tObject.defineProperty( this, 'power', {\n\t\tget: function () {\n\t\t\t// intensity = power per solid angle.\n\t\t\t// ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf\n\t\t\treturn this.intensity * 4 * Math.PI;\n\n\t\t},\n\t\tset: function ( power ) {\n\t\t\t// intensity = power per solid angle.\n\t\t\t// ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf\n\t\t\tthis.intensity = power / ( 4 * Math.PI );\n\t\t}\n\t} );\n\n\tthis.distance = ( distance !== undefined ) ? distance : 0;\n\tthis.decay = ( decay !== undefined ) ? decay : 1;\t// for physically correct lights, should be 2.\n\n\tthis.shadow = new LightShadow( new PerspectiveCamera( 90, 1, 0.5, 500 ) );\n\n}\n\nPointLight.prototype = Object.assign( Object.create( Light.prototype ), {\n\n\tconstructor: PointLight,\n\n\tisPointLight: true,\n\n\tcopy: function ( source ) {\n\n\t\tLight.prototype.copy.call( this, source );\n\n\t\tthis.distance = source.distance;\n\t\tthis.decay = source.decay;\n\n\t\tthis.shadow = source.shadow.clone();\n\n\t\treturn this;\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction DirectionalLightShadow( ) {\n\n\tLightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) );\n\n}\n\nDirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {\n\n\tconstructor: DirectionalLightShadow\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction DirectionalLight( color, intensity ) {\n\n\tLight.call( this, color, intensity );\n\n\tthis.type = 'DirectionalLight';\n\n\tthis.position.copy( Object3D.DefaultUp );\n\tthis.updateMatrix();\n\n\tthis.target = new Object3D();\n\n\tthis.shadow = new DirectionalLightShadow();\n\n}\n\nDirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), {\n\n\tconstructor: DirectionalLight,\n\n\tisDirectionalLight: true,\n\n\tcopy: function ( source ) {\n\n\t\tLight.prototype.copy.call( this, source );\n\n\t\tthis.target = source.target.clone();\n\n\t\tthis.shadow = source.shadow.clone();\n\n\t\treturn this;\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction AmbientLight( color, intensity ) {\n\n\tLight.call( this, color, intensity );\n\n\tthis.type = 'AmbientLight';\n\n\tthis.castShadow = undefined;\n\n}\n\nAmbientLight.prototype = Object.assign( Object.create( Light.prototype ), {\n\n\tconstructor: AmbientLight,\n\n\tisAmbientLight: true\n\n} );\n\n/**\n * @author tschw\n * @author Ben Houston / http://clara.io/\n * @author David Sarno / http://lighthaus.us/\n */\n\nvar AnimationUtils = {\n\n\t// same as Array.prototype.slice, but also works on typed arrays\n\tarraySlice: function( array, from, to ) {\n\n\t\tif ( AnimationUtils.isTypedArray( array ) ) {\n\n\t\t\treturn new array.constructor( array.subarray( from, to ) );\n\n\t\t}\n\n\t\treturn array.slice( from, to );\n\n\t},\n\n\t// converts an array to a specific type\n\tconvertArray: function( array, type, forceClone ) {\n\n\t\tif ( ! array || // let 'undefined' and 'null' pass\n\t\t\t\t! forceClone && array.constructor === type ) return array;\n\n\t\tif ( typeof type.BYTES_PER_ELEMENT === 'number' ) {\n\n\t\t\treturn new type( array ); // create typed array\n\n\t\t}\n\n\t\treturn Array.prototype.slice.call( array ); // create Array\n\n\t},\n\n\tisTypedArray: function( object ) {\n\n\t\treturn ArrayBuffer.isView( object ) &&\n\t\t\t\t! ( object instanceof DataView );\n\n\t},\n\n\t// returns an array by which times and values can be sorted\n\tgetKeyframeOrder: function( times ) {\n\n\t\tfunction compareTime( i, j ) {\n\n\t\t\treturn times[ i ] - times[ j ];\n\n\t\t}\n\n\t\tvar n = times.length;\n\t\tvar result = new Array( n );\n\t\tfor ( var i = 0; i !== n; ++ i ) result[ i ] = i;\n\n\t\tresult.sort( compareTime );\n\n\t\treturn result;\n\n\t},\n\n\t// uses the array previously returned by 'getKeyframeOrder' to sort data\n\tsortedArray: function( values, stride, order ) {\n\n\t\tvar nValues = values.length;\n\t\tvar result = new values.constructor( nValues );\n\n\t\tfor ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {\n\n\t\t\tvar srcOffset = order[ i ] * stride;\n\n\t\t\tfor ( var j = 0; j !== stride; ++ j ) {\n\n\t\t\t\tresult[ dstOffset ++ ] = values[ srcOffset + j ];\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn result;\n\n\t},\n\n\t// function for parsing AOS keyframe formats\n\tflattenJSON: function( jsonKeys, times, values, valuePropertyName ) {\n\n\t\tvar i = 1, key = jsonKeys[ 0 ];\n\n\t\twhile ( key !== undefined && key[ valuePropertyName ] === undefined ) {\n\n\t\t\tkey = jsonKeys[ i ++ ];\n\n\t\t}\n\n\t\tif ( key === undefined ) return; // no data\n\n\t\tvar value = key[ valuePropertyName ];\n\t\tif ( value === undefined ) return; // no data\n\n\t\tif ( Array.isArray( value ) ) {\n\n\t\t\tdo {\n\n\t\t\t\tvalue = key[ valuePropertyName ];\n\n\t\t\t\tif ( value !== undefined ) {\n\n\t\t\t\t\ttimes.push( key.time );\n\t\t\t\t\tvalues.push.apply( values, value ); // push all elements\n\n\t\t\t\t}\n\n\t\t\t\tkey = jsonKeys[ i ++ ];\n\n\t\t\t} while ( key !== undefined );\n\n\t\t} else if ( value.toArray !== undefined ) {\n\t\t\t// ...assume THREE.Math-ish\n\n\t\t\tdo {\n\n\t\t\t\tvalue = key[ valuePropertyName ];\n\n\t\t\t\tif ( value !== undefined ) {\n\n\t\t\t\t\ttimes.push( key.time );\n\t\t\t\t\tvalue.toArray( values, values.length );\n\n\t\t\t\t}\n\n\t\t\t\tkey = jsonKeys[ i ++ ];\n\n\t\t\t} while ( key !== undefined );\n\n\t\t} else {\n\t\t\t// otherwise push as-is\n\n\t\t\tdo {\n\n\t\t\t\tvalue = key[ valuePropertyName ];\n\n\t\t\t\tif ( value !== undefined ) {\n\n\t\t\t\t\ttimes.push( key.time );\n\t\t\t\t\tvalues.push( value );\n\n\t\t\t\t}\n\n\t\t\t\tkey = jsonKeys[ i ++ ];\n\n\t\t\t} while ( key !== undefined );\n\n\t\t}\n\n\t}\n\n};\n\n/**\n * Abstract base class of interpolants over parametric samples.\n *\n * The parameter domain is one dimensional, typically the time or a path\n * along a curve defined by the data.\n *\n * The sample values can have any dimensionality and derived classes may\n * apply special interpretations to the data.\n *\n * This class provides the interval seek in a Template Method, deferring\n * the actual interpolation to derived classes.\n *\n * Time complexity is O(1) for linear access crossing at most two points\n * and O(log N) for random access, where N is the number of positions.\n *\n * References:\n *\n * \t\thttp://www.oodesign.com/template-method-pattern.html\n *\n * @author tschw\n */\n\nfunction Interpolant(\n\t\tparameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\tthis.parameterPositions = parameterPositions;\n\tthis._cachedIndex = 0;\n\n\tthis.resultBuffer = resultBuffer !== undefined ?\n\t\t\tresultBuffer : new sampleValues.constructor( sampleSize );\n\tthis.sampleValues = sampleValues;\n\tthis.valueSize = sampleSize;\n\n}\n\nInterpolant.prototype = {\n\n\tconstructor: Interpolant,\n\n\tevaluate: function( t ) {\n\n\t\tvar pp = this.parameterPositions,\n\t\t\ti1 = this._cachedIndex,\n\n\t\t\tt1 = pp[ i1 ],\n\t\t\tt0 = pp[ i1 - 1 ];\n\n\t\tvalidate_interval: {\n\n\t\t\tseek: {\n\n\t\t\t\tvar right;\n\n\t\t\t\tlinear_scan: {\n//- See http://jsperf.com/comparison-to-undefined/3\n//- slower code:\n//-\n//- \t\t\t\tif ( t >= t1 || t1 === undefined ) {\n\t\t\t\t\tforward_scan: if ( ! ( t < t1 ) ) {\n\n\t\t\t\t\t\tfor ( var giveUpAt = i1 + 2; ;) {\n\n\t\t\t\t\t\t\tif ( t1 === undefined ) {\n\n\t\t\t\t\t\t\t\tif ( t < t0 ) break forward_scan;\n\n\t\t\t\t\t\t\t\t// after end\n\n\t\t\t\t\t\t\t\ti1 = pp.length;\n\t\t\t\t\t\t\t\tthis._cachedIndex = i1;\n\t\t\t\t\t\t\t\treturn this.afterEnd_( i1 - 1, t, t0 );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ( i1 === giveUpAt ) break; // this loop\n\n\t\t\t\t\t\t\tt0 = t1;\n\t\t\t\t\t\t\tt1 = pp[ ++ i1 ];\n\n\t\t\t\t\t\t\tif ( t < t1 ) {\n\n\t\t\t\t\t\t\t\t// we have arrived at the sought interval\n\t\t\t\t\t\t\t\tbreak seek;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// prepare binary search on the right side of the index\n\t\t\t\t\t\tright = pp.length;\n\t\t\t\t\t\tbreak linear_scan;\n\n\t\t\t\t\t}\n\n//- slower code:\n//-\t\t\t\t\tif ( t < t0 || t0 === undefined ) {\n\t\t\t\t\tif ( ! ( t >= t0 ) ) {\n\n\t\t\t\t\t\t// looping?\n\n\t\t\t\t\t\tvar t1global = pp[ 1 ];\n\n\t\t\t\t\t\tif ( t < t1global ) {\n\n\t\t\t\t\t\t\ti1 = 2; // + 1, using the scan for the details\n\t\t\t\t\t\t\tt0 = t1global;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// linear reverse scan\n\n\t\t\t\t\t\tfor ( var giveUpAt = i1 - 2; ;) {\n\n\t\t\t\t\t\t\tif ( t0 === undefined ) {\n\n\t\t\t\t\t\t\t\t// before start\n\n\t\t\t\t\t\t\t\tthis._cachedIndex = 0;\n\t\t\t\t\t\t\t\treturn this.beforeStart_( 0, t, t1 );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ( i1 === giveUpAt ) break; // this loop\n\n\t\t\t\t\t\t\tt1 = t0;\n\t\t\t\t\t\t\tt0 = pp[ -- i1 - 1 ];\n\n\t\t\t\t\t\t\tif ( t >= t0 ) {\n\n\t\t\t\t\t\t\t\t// we have arrived at the sought interval\n\t\t\t\t\t\t\t\tbreak seek;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// prepare binary search on the left side of the index\n\t\t\t\t\t\tright = i1;\n\t\t\t\t\t\ti1 = 0;\n\t\t\t\t\t\tbreak linear_scan;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// the interval is valid\n\n\t\t\t\t\tbreak validate_interval;\n\n\t\t\t\t} // linear scan\n\n\t\t\t\t// binary search\n\n\t\t\t\twhile ( i1 < right ) {\n\n\t\t\t\t\tvar mid = ( i1 + right ) >>> 1;\n\n\t\t\t\t\tif ( t < pp[ mid ] ) {\n\n\t\t\t\t\t\tright = mid;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\ti1 = mid + 1;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tt1 = pp[ i1 ];\n\t\t\t\tt0 = pp[ i1 - 1 ];\n\n\t\t\t\t// check boundary cases, again\n\n\t\t\t\tif ( t0 === undefined ) {\n\n\t\t\t\t\tthis._cachedIndex = 0;\n\t\t\t\t\treturn this.beforeStart_( 0, t, t1 );\n\n\t\t\t\t}\n\n\t\t\t\tif ( t1 === undefined ) {\n\n\t\t\t\t\ti1 = pp.length;\n\t\t\t\t\tthis._cachedIndex = i1;\n\t\t\t\t\treturn this.afterEnd_( i1 - 1, t0, t );\n\n\t\t\t\t}\n\n\t\t\t} // seek\n\n\t\t\tthis._cachedIndex = i1;\n\n\t\t\tthis.intervalChanged_( i1, t0, t1 );\n\n\t\t} // validate_interval\n\n\t\treturn this.interpolate_( i1, t0, t, t1 );\n\n\t},\n\n\tsettings: null, // optional, subclass-specific settings structure\n\t// Note: The indirection allows central control of many interpolants.\n\n\t// --- Protected interface\n\n\tDefaultSettings_: {},\n\n\tgetSettings_: function() {\n\n\t\treturn this.settings || this.DefaultSettings_;\n\n\t},\n\n\tcopySampleValue_: function( index ) {\n\n\t\t// copies a sample value to the result buffer\n\n\t\tvar result = this.resultBuffer,\n\t\t\tvalues = this.sampleValues,\n\t\t\tstride = this.valueSize,\n\t\t\toffset = index * stride;\n\n\t\tfor ( var i = 0; i !== stride; ++ i ) {\n\n\t\t\tresult[ i ] = values[ offset + i ];\n\n\t\t}\n\n\t\treturn result;\n\n\t},\n\n\t// Template methods for derived classes:\n\n\tinterpolate_: function( i1, t0, t, t1 ) {\n\n\t\tthrow new Error( \"call to abstract method\" );\n\t\t// implementations shall return this.resultBuffer\n\n\t},\n\n\tintervalChanged_: function( i1, t0, t1 ) {\n\n\t\t// empty\n\n\t}\n\n};\n\nObject.assign( Interpolant.prototype, {\n\n\tbeforeStart_: //( 0, t, t0 ), returns this.resultBuffer\n\t\tInterpolant.prototype.copySampleValue_,\n\n\tafterEnd_: //( N-1, tN-1, t ), returns this.resultBuffer\n\t\tInterpolant.prototype.copySampleValue_\n\n} );\n\n/**\n * Fast and simple cubic spline interpolant.\n *\n * It was derived from a Hermitian construction setting the first derivative\n * at each sample position to the linear slope between neighboring positions\n * over their parameter interval.\n *\n * @author tschw\n */\n\nfunction CubicInterpolant(\n\t\tparameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\tInterpolant.call(\n\t\t\tthis, parameterPositions, sampleValues, sampleSize, resultBuffer );\n\n\tthis._weightPrev = -0;\n\tthis._offsetPrev = -0;\n\tthis._weightNext = -0;\n\tthis._offsetNext = -0;\n\n}\n\nCubicInterpolant.prototype =\n\t\tObject.assign( Object.create( Interpolant.prototype ), {\n\n\tconstructor: CubicInterpolant,\n\n\tDefaultSettings_: {\n\n\t\tendingStart: \tZeroCurvatureEnding,\n\t\tendingEnd:\t\tZeroCurvatureEnding\n\n\t},\n\n\tintervalChanged_: function( i1, t0, t1 ) {\n\n\t\tvar pp = this.parameterPositions,\n\t\t\tiPrev = i1 - 2,\n\t\t\tiNext = i1 + 1,\n\n\t\t\ttPrev = pp[ iPrev ],\n\t\t\ttNext = pp[ iNext ];\n\n\t\tif ( tPrev === undefined ) {\n\n\t\t\tswitch ( this.getSettings_().endingStart ) {\n\n\t\t\t\tcase ZeroSlopeEnding:\n\n\t\t\t\t\t// f'(t0) = 0\n\t\t\t\t\tiPrev = i1;\n\t\t\t\t\ttPrev = 2 * t0 - t1;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase WrapAroundEnding:\n\n\t\t\t\t\t// use the other end of the curve\n\t\t\t\t\tiPrev = pp.length - 2;\n\t\t\t\t\ttPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault: // ZeroCurvatureEnding\n\n\t\t\t\t\t// f''(t0) = 0 a.k.a. Natural Spline\n\t\t\t\t\tiPrev = i1;\n\t\t\t\t\ttPrev = t1;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( tNext === undefined ) {\n\n\t\t\tswitch ( this.getSettings_().endingEnd ) {\n\n\t\t\t\tcase ZeroSlopeEnding:\n\n\t\t\t\t\t// f'(tN) = 0\n\t\t\t\t\tiNext = i1;\n\t\t\t\t\ttNext = 2 * t1 - t0;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase WrapAroundEnding:\n\n\t\t\t\t\t// use the other end of the curve\n\t\t\t\t\tiNext = 1;\n\t\t\t\t\ttNext = t1 + pp[ 1 ] - pp[ 0 ];\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault: // ZeroCurvatureEnding\n\n\t\t\t\t\t// f''(tN) = 0, a.k.a. Natural Spline\n\t\t\t\t\tiNext = i1 - 1;\n\t\t\t\t\ttNext = t0;\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar halfDt = ( t1 - t0 ) * 0.5,\n\t\t\tstride = this.valueSize;\n\n\t\tthis._weightPrev = halfDt / ( t0 - tPrev );\n\t\tthis._weightNext = halfDt / ( tNext - t1 );\n\t\tthis._offsetPrev = iPrev * stride;\n\t\tthis._offsetNext = iNext * stride;\n\n\t},\n\n\tinterpolate_: function( i1, t0, t, t1 ) {\n\n\t\tvar result = this.resultBuffer,\n\t\t\tvalues = this.sampleValues,\n\t\t\tstride = this.valueSize,\n\n\t\t\to1 = i1 * stride,\t\to0 = o1 - stride,\n\t\t\toP = this._offsetPrev, \toN = this._offsetNext,\n\t\t\twP = this._weightPrev,\twN = this._weightNext,\n\n\t\t\tp = ( t - t0 ) / ( t1 - t0 ),\n\t\t\tpp = p * p,\n\t\t\tppp = pp * p;\n\n\t\t// evaluate polynomials\n\n\t\tvar sP = - wP * ppp + 2 * wP * pp - wP * p;\n\t\tvar s0 = ( 1 + wP ) * ppp + (-1.5 - 2 * wP ) * pp + ( -0.5 + wP ) * p + 1;\n\t\tvar s1 = (-1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p;\n\t\tvar sN = wN * ppp - wN * pp;\n\n\t\t// combine data linearly\n\n\t\tfor ( var i = 0; i !== stride; ++ i ) {\n\n\t\t\tresult[ i ] =\n\t\t\t\t\tsP * values[ oP + i ] +\n\t\t\t\t\ts0 * values[ o0 + i ] +\n\t\t\t\t\ts1 * values[ o1 + i ] +\n\t\t\t\t\tsN * values[ oN + i ];\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n} );\n\n/**\n * @author tschw\n */\n\nfunction LinearInterpolant(\n\t\tparameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\tInterpolant.call(\n\t\t\tthis, parameterPositions, sampleValues, sampleSize, resultBuffer );\n\n}\n\nLinearInterpolant.prototype =\n\t\tObject.assign( Object.create( Interpolant.prototype ), {\n\n\tconstructor: LinearInterpolant,\n\n\tinterpolate_: function( i1, t0, t, t1 ) {\n\n\t\tvar result = this.resultBuffer,\n\t\t\tvalues = this.sampleValues,\n\t\t\tstride = this.valueSize,\n\n\t\t\toffset1 = i1 * stride,\n\t\t\toffset0 = offset1 - stride,\n\n\t\t\tweight1 = ( t - t0 ) / ( t1 - t0 ),\n\t\t\tweight0 = 1 - weight1;\n\n\t\tfor ( var i = 0; i !== stride; ++ i ) {\n\n\t\t\tresult[ i ] =\n\t\t\t\t\tvalues[ offset0 + i ] * weight0 +\n\t\t\t\t\tvalues[ offset1 + i ] * weight1;\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n} );\n\n/**\n *\n * Interpolant that evaluates to the sample value at the position preceeding\n * the parameter.\n *\n * @author tschw\n */\n\nfunction DiscreteInterpolant(\n\t\tparameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\tInterpolant.call(\n\t\t\tthis, parameterPositions, sampleValues, sampleSize, resultBuffer );\n\n}\n\nDiscreteInterpolant.prototype =\n\t\tObject.assign( Object.create( Interpolant.prototype ), {\n\n\tconstructor: DiscreteInterpolant,\n\n\tinterpolate_: function( i1, t0, t, t1 ) {\n\n\t\treturn this.copySampleValue_( i1 - 1 );\n\n\t}\n\n} );\n\nvar KeyframeTrackPrototype;\n\nKeyframeTrackPrototype = {\n\n\tTimeBufferType: Float32Array,\n\tValueBufferType: Float32Array,\n\n\tDefaultInterpolation: InterpolateLinear,\n\n\tInterpolantFactoryMethodDiscrete: function ( result ) {\n\n\t\treturn new DiscreteInterpolant(\n\t\t\t\tthis.times, this.values, this.getValueSize(), result );\n\n\t},\n\n\tInterpolantFactoryMethodLinear: function ( result ) {\n\n\t\treturn new LinearInterpolant(\n\t\t\t\tthis.times, this.values, this.getValueSize(), result );\n\n\t},\n\n\tInterpolantFactoryMethodSmooth: function ( result ) {\n\n\t\treturn new CubicInterpolant(\n\t\t\t\tthis.times, this.values, this.getValueSize(), result );\n\n\t},\n\n\tsetInterpolation: function ( interpolation ) {\n\n\t\tvar factoryMethod;\n\n\t\tswitch ( interpolation ) {\n\n\t\t\tcase InterpolateDiscrete:\n\n\t\t\t\tfactoryMethod = this.InterpolantFactoryMethodDiscrete;\n\n\t\t\t\tbreak;\n\n\t\t\tcase InterpolateLinear:\n\n\t\t\t\tfactoryMethod = this.InterpolantFactoryMethodLinear;\n\n\t\t\t\tbreak;\n\n\t\t\tcase InterpolateSmooth:\n\n\t\t\t\tfactoryMethod = this.InterpolantFactoryMethodSmooth;\n\n\t\t\t\tbreak;\n\n\t\t}\n\n\t\tif ( factoryMethod === undefined ) {\n\n\t\t\tvar message = \"unsupported interpolation for \" +\n\t\t\t\t\tthis.ValueTypeName + \" keyframe track named \" + this.name;\n\n\t\t\tif ( this.createInterpolant === undefined ) {\n\n\t\t\t\t// fall back to default, unless the default itself is messed up\n\t\t\t\tif ( interpolation !== this.DefaultInterpolation ) {\n\n\t\t\t\t\tthis.setInterpolation( this.DefaultInterpolation );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthrow new Error( message ); // fatal, in this case\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconsole.warn( message );\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis.createInterpolant = factoryMethod;\n\n\t},\n\n\tgetInterpolation: function () {\n\n\t\tswitch ( this.createInterpolant ) {\n\n\t\t\tcase this.InterpolantFactoryMethodDiscrete:\n\n\t\t\t\treturn InterpolateDiscrete;\n\n\t\t\tcase this.InterpolantFactoryMethodLinear:\n\n\t\t\t\treturn InterpolateLinear;\n\n\t\t\tcase this.InterpolantFactoryMethodSmooth:\n\n\t\t\t\treturn InterpolateSmooth;\n\n\t\t}\n\n\t},\n\n\tgetValueSize: function () {\n\n\t\treturn this.values.length / this.times.length;\n\n\t},\n\n\t// move all keyframes either forwards or backwards in time\n\tshift: function ( timeOffset ) {\n\n\t\tif ( timeOffset !== 0.0 ) {\n\n\t\t\tvar times = this.times;\n\n\t\t\tfor ( var i = 0, n = times.length; i !== n; ++ i ) {\n\n\t\t\t\ttimes[ i ] += timeOffset;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\t// scale all keyframe times by a factor (useful for frame <-> seconds conversions)\n\tscale: function ( timeScale ) {\n\n\t\tif ( timeScale !== 1.0 ) {\n\n\t\t\tvar times = this.times;\n\n\t\t\tfor ( var i = 0, n = times.length; i !== n; ++ i ) {\n\n\t\t\t\ttimes[ i ] *= timeScale;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\t// removes keyframes before and after animation without changing any values within the range [startTime, endTime].\n\t// IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values\n\ttrim: function ( startTime, endTime ) {\n\n\t\tvar times = this.times,\n\t\t\tnKeys = times.length,\n\t\t\tfrom = 0,\n\t\t\tto = nKeys - 1;\n\n\t\twhile ( from !== nKeys && times[ from ] < startTime ) ++ from;\n\t\twhile ( to !== - 1 && times[ to ] > endTime ) -- to;\n\n\t\t++ to; // inclusive -> exclusive bound\n\n\t\tif ( from !== 0 || to !== nKeys ) {\n\n\t\t\t// empty tracks are forbidden, so keep at least one keyframe\n\t\t\tif ( from >= to ) to = Math.max( to, 1 ), from = to - 1;\n\n\t\t\tvar stride = this.getValueSize();\n\t\t\tthis.times = AnimationUtils.arraySlice( times, from, to );\n\t\t\tthis.values = AnimationUtils.\n\t\t\t\t\tarraySlice( this.values, from * stride, to * stride );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\t// ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable\n\tvalidate: function () {\n\n\t\tvar valid = true;\n\n\t\tvar valueSize = this.getValueSize();\n\t\tif ( valueSize - Math.floor( valueSize ) !== 0 ) {\n\n\t\t\tconsole.error( \"invalid value size in track\", this );\n\t\t\tvalid = false;\n\n\t\t}\n\n\t\tvar times = this.times,\n\t\t\tvalues = this.values,\n\n\t\t\tnKeys = times.length;\n\n\t\tif ( nKeys === 0 ) {\n\n\t\t\tconsole.error( \"track is empty\", this );\n\t\t\tvalid = false;\n\n\t\t}\n\n\t\tvar prevTime = null;\n\n\t\tfor ( var i = 0; i !== nKeys; i ++ ) {\n\n\t\t\tvar currTime = times[ i ];\n\n\t\t\tif ( typeof currTime === 'number' && isNaN( currTime ) ) {\n\n\t\t\t\tconsole.error( \"time is not a valid number\", this, i, currTime );\n\t\t\t\tvalid = false;\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tif ( prevTime !== null && prevTime > currTime ) {\n\n\t\t\t\tconsole.error( \"out of order keys\", this, i, currTime, prevTime );\n\t\t\t\tvalid = false;\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tprevTime = currTime;\n\n\t\t}\n\n\t\tif ( values !== undefined ) {\n\n\t\t\tif ( AnimationUtils.isTypedArray( values ) ) {\n\n\t\t\t\tfor ( var i = 0, n = values.length; i !== n; ++ i ) {\n\n\t\t\t\t\tvar value = values[ i ];\n\n\t\t\t\t\tif ( isNaN( value ) ) {\n\n\t\t\t\t\t\tconsole.error( \"value is not a valid number\", this, i, value );\n\t\t\t\t\t\tvalid = false;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn valid;\n\n\t},\n\n\t// removes equivalent sequential keys as common in morph target sequences\n\t// (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)\n\toptimize: function () {\n\n\t\tvar times = this.times,\n\t\t\tvalues = this.values,\n\t\t\tstride = this.getValueSize(),\n\n\t\t\tsmoothInterpolation = this.getInterpolation() === InterpolateSmooth,\n\n\t\t\twriteIndex = 1,\n\t\t\tlastIndex = times.length - 1;\n\n\t\tfor ( var i = 1; i < lastIndex; ++ i ) {\n\n\t\t\tvar keep = false;\n\n\t\t\tvar time = times[ i ];\n\t\t\tvar timeNext = times[ i + 1 ];\n\n\t\t\t// remove adjacent keyframes scheduled at the same time\n\n\t\t\tif ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) {\n\n\t\t\t\tif ( ! smoothInterpolation ) {\n\n\t\t\t\t\t// remove unnecessary keyframes same as their neighbors\n\n\t\t\t\t\tvar offset = i * stride,\n\t\t\t\t\t\toffsetP = offset - stride,\n\t\t\t\t\t\toffsetN = offset + stride;\n\n\t\t\t\t\tfor ( var j = 0; j !== stride; ++ j ) {\n\n\t\t\t\t\t\tvar value = values[ offset + j ];\n\n\t\t\t\t\t\tif ( value !== values[ offsetP + j ] ||\n\t\t\t\t\t\t\t\tvalue !== values[ offsetN + j ] ) {\n\n\t\t\t\t\t\t\tkeep = true;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else keep = true;\n\n\t\t\t}\n\n\t\t\t// in-place compaction\n\n\t\t\tif ( keep ) {\n\n\t\t\t\tif ( i !== writeIndex ) {\n\n\t\t\t\t\ttimes[ writeIndex ] = times[ i ];\n\n\t\t\t\t\tvar readOffset = i * stride,\n\t\t\t\t\t\twriteOffset = writeIndex * stride;\n\n\t\t\t\t\tfor ( var j = 0; j !== stride; ++ j )\n\n\t\t\t\t\t\tvalues[ writeOffset + j ] = values[ readOffset + j ];\n\n\t\t\t\t}\n\n\t\t\t\t++ writeIndex;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// flush last keyframe (compaction looks ahead)\n\n\t\tif ( lastIndex > 0 ) {\n\n\t\t\ttimes[ writeIndex ] = times[ lastIndex ];\n\n\t\t\tfor ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j )\n\n\t\t\t\tvalues[ writeOffset + j ] = values[ readOffset + j ];\n\n\t\t\t++ writeIndex;\n\n\t\t}\n\n\t\tif ( writeIndex !== times.length ) {\n\n\t\t\tthis.times = AnimationUtils.arraySlice( times, 0, writeIndex );\n\t\t\tthis.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n};\n\nfunction KeyframeTrackConstructor( name, times, values, interpolation ) {\n\n\tif( name === undefined ) throw new Error( \"track name is undefined\" );\n\n\tif( times === undefined || times.length === 0 ) {\n\n\t\tthrow new Error( \"no keyframes in track named \" + name );\n\n\t}\n\n\tthis.name = name;\n\n\tthis.times = AnimationUtils.convertArray( times, this.TimeBufferType );\n\tthis.values = AnimationUtils.convertArray( values, this.ValueBufferType );\n\n\tthis.setInterpolation( interpolation || this.DefaultInterpolation );\n\n\tthis.validate();\n\tthis.optimize();\n\n}\n\n/**\n *\n * A Track of vectored keyframe values.\n *\n *\n * @author Ben Houston / http://clara.io/\n * @author David Sarno / http://lighthaus.us/\n * @author tschw\n */\n\nfunction VectorKeyframeTrack( name, times, values, interpolation ) {\n\n\tKeyframeTrackConstructor.call( this, name, times, values, interpolation );\n\n}\n\nVectorKeyframeTrack.prototype =\n\t\tObject.assign( Object.create( KeyframeTrackPrototype ), {\n\n\tconstructor: VectorKeyframeTrack,\n\n\tValueTypeName: 'vector'\n\n\t// ValueBufferType is inherited\n\n\t// DefaultInterpolation is inherited\n\n} );\n\n/**\n * Spherical linear unit quaternion interpolant.\n *\n * @author tschw\n */\n\nfunction QuaternionLinearInterpolant(\n\t\tparameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\tInterpolant.call(\n\t\t\tthis, parameterPositions, sampleValues, sampleSize, resultBuffer );\n\n}\n\nQuaternionLinearInterpolant.prototype =\n\t\tObject.assign( Object.create( Interpolant.prototype ), {\n\n\tconstructor: QuaternionLinearInterpolant,\n\n\tinterpolate_: function( i1, t0, t, t1 ) {\n\n\t\tvar result = this.resultBuffer,\n\t\t\tvalues = this.sampleValues,\n\t\t\tstride = this.valueSize,\n\n\t\t\toffset = i1 * stride,\n\n\t\t\talpha = ( t - t0 ) / ( t1 - t0 );\n\n\t\tfor ( var end = offset + stride; offset !== end; offset += 4 ) {\n\n\t\t\tQuaternion.slerpFlat( result, 0,\n\t\t\t\t\tvalues, offset - stride, values, offset, alpha );\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n} );\n\n/**\n *\n * A Track of quaternion keyframe values.\n *\n * @author Ben Houston / http://clara.io/\n * @author David Sarno / http://lighthaus.us/\n * @author tschw\n */\n\nfunction QuaternionKeyframeTrack( name, times, values, interpolation ) {\n\n\tKeyframeTrackConstructor.call( this, name, times, values, interpolation );\n\n}\n\nQuaternionKeyframeTrack.prototype =\n\t\tObject.assign( Object.create( KeyframeTrackPrototype ), {\n\n\tconstructor: QuaternionKeyframeTrack,\n\n\tValueTypeName: 'quaternion',\n\n\t// ValueBufferType is inherited\n\n\tDefaultInterpolation: InterpolateLinear,\n\n\tInterpolantFactoryMethodLinear: function( result ) {\n\n\t\treturn new QuaternionLinearInterpolant(\n\t\t\t\tthis.times, this.values, this.getValueSize(), result );\n\n\t},\n\n\tInterpolantFactoryMethodSmooth: undefined // not yet implemented\n\n} );\n\n/**\n *\n * A Track of numeric keyframe values.\n *\n * @author Ben Houston / http://clara.io/\n * @author David Sarno / http://lighthaus.us/\n * @author tschw\n */\n\nfunction NumberKeyframeTrack( name, times, values, interpolation ) {\n\n\tKeyframeTrackConstructor.call( this, name, times, values, interpolation );\n\n}\n\nNumberKeyframeTrack.prototype =\n\t\tObject.assign( Object.create( KeyframeTrackPrototype ), {\n\n\tconstructor: NumberKeyframeTrack,\n\n\tValueTypeName: 'number'\n\n\t// ValueBufferType is inherited\n\n\t// DefaultInterpolation is inherited\n\n} );\n\n/**\n *\n * A Track that interpolates Strings\n *\n *\n * @author Ben Houston / http://clara.io/\n * @author David Sarno / http://lighthaus.us/\n * @author tschw\n */\n\nfunction StringKeyframeTrack( name, times, values, interpolation ) {\n\n\tKeyframeTrackConstructor.call( this, name, times, values, interpolation );\n\n}\n\nStringKeyframeTrack.prototype =\n\t\tObject.assign( Object.create( KeyframeTrackPrototype ), {\n\n\tconstructor: StringKeyframeTrack,\n\n\tValueTypeName: 'string',\n\tValueBufferType: Array,\n\n\tDefaultInterpolation: InterpolateDiscrete,\n\n\tInterpolantFactoryMethodLinear: undefined,\n\n\tInterpolantFactoryMethodSmooth: undefined\n\n} );\n\n/**\n *\n * A Track of Boolean keyframe values.\n *\n *\n * @author Ben Houston / http://clara.io/\n * @author David Sarno / http://lighthaus.us/\n * @author tschw\n */\n\nfunction BooleanKeyframeTrack( name, times, values ) {\n\n\tKeyframeTrackConstructor.call( this, name, times, values );\n\n}\n\nBooleanKeyframeTrack.prototype =\n\t\tObject.assign( Object.create( KeyframeTrackPrototype ), {\n\n\tconstructor: BooleanKeyframeTrack,\n\n\tValueTypeName: 'bool',\n\tValueBufferType: Array,\n\n\tDefaultInterpolation: InterpolateDiscrete,\n\n\tInterpolantFactoryMethodLinear: undefined,\n\tInterpolantFactoryMethodSmooth: undefined\n\n\t// Note: Actually this track could have a optimized / compressed\n\t// representation of a single value and a custom interpolant that\n\t// computes \"firstValue ^ isOdd( index )\".\n\n} );\n\n/**\n *\n * A Track of keyframe values that represent color.\n *\n *\n * @author Ben Houston / http://clara.io/\n * @author David Sarno / http://lighthaus.us/\n * @author tschw\n */\n\nfunction ColorKeyframeTrack( name, times, values, interpolation ) {\n\n\tKeyframeTrackConstructor.call( this, name, times, values, interpolation );\n\n}\n\nColorKeyframeTrack.prototype =\n\t\tObject.assign( Object.create( KeyframeTrackPrototype ), {\n\n\tconstructor: ColorKeyframeTrack,\n\n\tValueTypeName: 'color'\n\n\t// ValueBufferType is inherited\n\n\t// DefaultInterpolation is inherited\n\n\n\t// Note: Very basic implementation and nothing special yet.\n\t// However, this is the place for color space parameterization.\n\n} );\n\n/**\n *\n * A timed sequence of keyframes for a specific property.\n *\n *\n * @author Ben Houston / http://clara.io/\n * @author David Sarno / http://lighthaus.us/\n * @author tschw\n */\n\nfunction KeyframeTrack( name, times, values, interpolation ) {\n\n\tKeyframeTrackConstructor.apply( this, arguments );\n\n}\n\nKeyframeTrack.prototype = KeyframeTrackPrototype;\nKeyframeTrackPrototype.constructor = KeyframeTrack;\n\n// Static methods:\n\nObject.assign( KeyframeTrack, {\n\n\t// Serialization (in static context, because of constructor invocation\n\t// and automatic invocation of .toJSON):\n\n\tparse: function( json ) {\n\n\t\tif( json.type === undefined ) {\n\n\t\t\tthrow new Error( \"track type undefined, can not parse\" );\n\n\t\t}\n\n\t\tvar trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type );\n\n\t\tif ( json.times === undefined ) {\n\n\t\t\tvar times = [], values = [];\n\n\t\t\tAnimationUtils.flattenJSON( json.keys, times, values, 'value' );\n\n\t\t\tjson.times = times;\n\t\t\tjson.values = values;\n\n\t\t}\n\n\t\t// derived classes can define a static parse method\n\t\tif ( trackType.parse !== undefined ) {\n\n\t\t\treturn trackType.parse( json );\n\n\t\t} else {\n\n\t\t\t// by default, we asssume a constructor compatible with the base\n\t\t\treturn new trackType(\n\t\t\t\t\tjson.name, json.times, json.values, json.interpolation );\n\n\t\t}\n\n\t},\n\n\ttoJSON: function( track ) {\n\n\t\tvar trackType = track.constructor;\n\n\t\tvar json;\n\n\t\t// derived classes can define a static toJSON method\n\t\tif ( trackType.toJSON !== undefined ) {\n\n\t\t\tjson = trackType.toJSON( track );\n\n\t\t} else {\n\n\t\t\t// by default, we assume the data can be serialized as-is\n\t\t\tjson = {\n\n\t\t\t\t'name': track.name,\n\t\t\t\t'times': AnimationUtils.convertArray( track.times, Array ),\n\t\t\t\t'values': AnimationUtils.convertArray( track.values, Array )\n\n\t\t\t};\n\n\t\t\tvar interpolation = track.getInterpolation();\n\n\t\t\tif ( interpolation !== track.DefaultInterpolation ) {\n\n\t\t\t\tjson.interpolation = interpolation;\n\n\t\t\t}\n\n\t\t}\n\n\t\tjson.type = track.ValueTypeName; // mandatory\n\n\t\treturn json;\n\n\t},\n\n\t_getTrackTypeForValueTypeName: function( typeName ) {\n\n\t\tswitch( typeName.toLowerCase() ) {\n\n\t\t\tcase \"scalar\":\n\t\t\tcase \"double\":\n\t\t\tcase \"float\":\n\t\t\tcase \"number\":\n\t\t\tcase \"integer\":\n\n\t\t\t\treturn NumberKeyframeTrack;\n\n\t\t\tcase \"vector\":\n\t\t\tcase \"vector2\":\n\t\t\tcase \"vector3\":\n\t\t\tcase \"vector4\":\n\n\t\t\t\treturn VectorKeyframeTrack;\n\n\t\t\tcase \"color\":\n\n\t\t\t\treturn ColorKeyframeTrack;\n\n\t\t\tcase \"quaternion\":\n\n\t\t\t\treturn QuaternionKeyframeTrack;\n\n\t\t\tcase \"bool\":\n\t\t\tcase \"boolean\":\n\n\t\t\t\treturn BooleanKeyframeTrack;\n\n\t\t\tcase \"string\":\n\n\t\t\t\treturn StringKeyframeTrack;\n\n\t\t}\n\n\t\tthrow new Error( \"Unsupported typeName: \" + typeName );\n\n\t}\n\n} );\n\n/**\n *\n * Reusable set of Tracks that represent an animation.\n *\n * @author Ben Houston / http://clara.io/\n * @author David Sarno / http://lighthaus.us/\n */\n\nfunction AnimationClip( name, duration, tracks ) {\n\n\tthis.name = name;\n\tthis.tracks = tracks;\n\tthis.duration = ( duration !== undefined ) ? duration : -1;\n\n\tthis.uuid = _Math.generateUUID();\n\n\t// this means it should figure out its duration by scanning the tracks\n\tif ( this.duration < 0 ) {\n\n\t\tthis.resetDuration();\n\n\t}\n\n\tthis.optimize();\n\n}\n\nAnimationClip.prototype = {\n\n\tconstructor: AnimationClip,\n\n\tresetDuration: function() {\n\n\t\tvar tracks = this.tracks,\n\t\t\tduration = 0;\n\n\t\tfor ( var i = 0, n = tracks.length; i !== n; ++ i ) {\n\n\t\t\tvar track = this.tracks[ i ];\n\n\t\t\tduration = Math.max( duration, track.times[ track.times.length - 1 ] );\n\n\t\t}\n\n\t\tthis.duration = duration;\n\n\t},\n\n\ttrim: function() {\n\n\t\tfor ( var i = 0; i < this.tracks.length; i ++ ) {\n\n\t\t\tthis.tracks[ i ].trim( 0, this.duration );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\toptimize: function() {\n\n\t\tfor ( var i = 0; i < this.tracks.length; i ++ ) {\n\n\t\t\tthis.tracks[ i ].optimize();\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n};\n\n// Static methods:\n\nObject.assign( AnimationClip, {\n\n\tparse: function( json ) {\n\n\t\tvar tracks = [],\n\t\t\tjsonTracks = json.tracks,\n\t\t\tframeTime = 1.0 / ( json.fps || 1.0 );\n\n\t\tfor ( var i = 0, n = jsonTracks.length; i !== n; ++ i ) {\n\n\t\t\ttracks.push( KeyframeTrack.parse( jsonTracks[ i ] ).scale( frameTime ) );\n\n\t\t}\n\n\t\treturn new AnimationClip( json.name, json.duration, tracks );\n\n\t},\n\n\n\ttoJSON: function( clip ) {\n\n\t\tvar tracks = [],\n\t\t\tclipTracks = clip.tracks;\n\n\t\tvar json = {\n\n\t\t\t'name': clip.name,\n\t\t\t'duration': clip.duration,\n\t\t\t'tracks': tracks\n\n\t\t};\n\n\t\tfor ( var i = 0, n = clipTracks.length; i !== n; ++ i ) {\n\n\t\t\ttracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) );\n\n\t\t}\n\n\t\treturn json;\n\n\t},\n\n\n\tCreateFromMorphTargetSequence: function( name, morphTargetSequence, fps, noLoop ) {\n\n\t\tvar numMorphTargets = morphTargetSequence.length;\n\t\tvar tracks = [];\n\n\t\tfor ( var i = 0; i < numMorphTargets; i ++ ) {\n\n\t\t\tvar times = [];\n\t\t\tvar values = [];\n\n\t\t\ttimes.push(\n\t\t\t\t\t( i + numMorphTargets - 1 ) % numMorphTargets,\n\t\t\t\t\ti,\n\t\t\t\t\t( i + 1 ) % numMorphTargets );\n\n\t\t\tvalues.push( 0, 1, 0 );\n\n\t\t\tvar order = AnimationUtils.getKeyframeOrder( times );\n\t\t\ttimes = AnimationUtils.sortedArray( times, 1, order );\n\t\t\tvalues = AnimationUtils.sortedArray( values, 1, order );\n\n\t\t\t// if there is a key at the first frame, duplicate it as the\n\t\t\t// last frame as well for perfect loop.\n\t\t\tif ( ! noLoop && times[ 0 ] === 0 ) {\n\n\t\t\t\ttimes.push( numMorphTargets );\n\t\t\t\tvalues.push( values[ 0 ] );\n\n\t\t\t}\n\n\t\t\ttracks.push(\n\t\t\t\t\tnew NumberKeyframeTrack(\n\t\t\t\t\t\t'.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']',\n\t\t\t\t\t\ttimes, values\n\t\t\t\t\t).scale( 1.0 / fps ) );\n\t\t}\n\n\t\treturn new AnimationClip( name, -1, tracks );\n\n\t},\n\n\tfindByName: function( objectOrClipArray, name ) {\n\n\t\tvar clipArray = objectOrClipArray;\n\n\t\tif ( ! Array.isArray( objectOrClipArray ) ) {\n\n\t\t\tvar o = objectOrClipArray;\n\t\t\tclipArray = o.geometry && o.geometry.animations || o.animations;\n\n\t\t}\n\n\t\tfor ( var i = 0; i < clipArray.length; i ++ ) {\n\n\t\t\tif ( clipArray[ i ].name === name ) {\n\n\t\t\t\treturn clipArray[ i ];\n\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\n\t},\n\n\tCreateClipsFromMorphTargetSequences: function( morphTargets, fps, noLoop ) {\n\n\t\tvar animationToMorphTargets = {};\n\n\t\t// tested with https://regex101.com/ on trick sequences\n\t\t// such flamingo_flyA_003, flamingo_run1_003, crdeath0059\n\t\tvar pattern = /^([\\w-]*?)([\\d]+)$/;\n\n\t\t// sort morph target names into animation groups based\n\t\t// patterns like Walk_001, Walk_002, Run_001, Run_002\n\t\tfor ( var i = 0, il = morphTargets.length; i < il; i ++ ) {\n\n\t\t\tvar morphTarget = morphTargets[ i ];\n\t\t\tvar parts = morphTarget.name.match( pattern );\n\n\t\t\tif ( parts && parts.length > 1 ) {\n\n\t\t\t\tvar name = parts[ 1 ];\n\n\t\t\t\tvar animationMorphTargets = animationToMorphTargets[ name ];\n\t\t\t\tif ( ! animationMorphTargets ) {\n\n\t\t\t\t\tanimationToMorphTargets[ name ] = animationMorphTargets = [];\n\n\t\t\t\t}\n\n\t\t\t\tanimationMorphTargets.push( morphTarget );\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar clips = [];\n\n\t\tfor ( var name in animationToMorphTargets ) {\n\n\t\t\tclips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) );\n\n\t\t}\n\n\t\treturn clips;\n\n\t},\n\n\t// parse the animation.hierarchy format\n\tparseAnimation: function( animation, bones ) {\n\n\t\tif ( ! animation ) {\n\n\t\t\tconsole.error( \" no animation in JSONLoader data\" );\n\t\t\treturn null;\n\n\t\t}\n\n\t\tvar addNonemptyTrack = function(\n\t\t\t\ttrackType, trackName, animationKeys, propertyName, destTracks ) {\n\n\t\t\t// only return track if there are actually keys.\n\t\t\tif ( animationKeys.length !== 0 ) {\n\n\t\t\t\tvar times = [];\n\t\t\t\tvar values = [];\n\n\t\t\t\tAnimationUtils.flattenJSON(\n\t\t\t\t\t\tanimationKeys, times, values, propertyName );\n\n\t\t\t\t// empty keys are filtered out, so check again\n\t\t\t\tif ( times.length !== 0 ) {\n\n\t\t\t\t\tdestTracks.push( new trackType( trackName, times, values ) );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t\tvar tracks = [];\n\n\t\tvar clipName = animation.name || 'default';\n\t\t// automatic length determination in AnimationClip.\n\t\tvar duration = animation.length || -1;\n\t\tvar fps = animation.fps || 30;\n\n\t\tvar hierarchyTracks = animation.hierarchy || [];\n\n\t\tfor ( var h = 0; h < hierarchyTracks.length; h ++ ) {\n\n\t\t\tvar animationKeys = hierarchyTracks[ h ].keys;\n\n\t\t\t// skip empty tracks\n\t\t\tif ( ! animationKeys || animationKeys.length === 0 ) continue;\n\n\t\t\t// process morph targets in a way exactly compatible\n\t\t\t// with AnimationHandler.init( animation )\n\t\t\tif ( animationKeys[0].morphTargets ) {\n\n\t\t\t\t// figure out all morph targets used in this track\n\t\t\t\tvar morphTargetNames = {};\n\t\t\t\tfor ( var k = 0; k < animationKeys.length; k ++ ) {\n\n\t\t\t\t\tif ( animationKeys[k].morphTargets ) {\n\n\t\t\t\t\t\tfor ( var m = 0; m < animationKeys[k].morphTargets.length; m ++ ) {\n\n\t\t\t\t\t\t\tmorphTargetNames[ animationKeys[k].morphTargets[m] ] = -1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t// create a track for each morph target with all zero\n\t\t\t\t// morphTargetInfluences except for the keys in which\n\t\t\t\t// the morphTarget is named.\n\t\t\t\tfor ( var morphTargetName in morphTargetNames ) {\n\n\t\t\t\t\tvar times = [];\n\t\t\t\t\tvar values = [];\n\n\t\t\t\t\tfor ( var m = 0; m !== animationKeys[k].morphTargets.length; ++ m ) {\n\n\t\t\t\t\t\tvar animationKey = animationKeys[k];\n\n\t\t\t\t\t\ttimes.push( animationKey.time );\n\t\t\t\t\t\tvalues.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttracks.push( new NumberKeyframeTrack('.morphTargetInfluence[' + morphTargetName + ']', times, values ) );\n\n\t\t\t\t}\n\n\t\t\t\tduration = morphTargetNames.length * ( fps || 1.0 );\n\n\t\t\t} else {\n\t\t\t\t// ...assume skeletal animation\n\n\t\t\t\tvar boneName = '.bones[' + bones[ h ].name + ']';\n\n\t\t\t\taddNonemptyTrack(\n\t\t\t\t\t\tVectorKeyframeTrack, boneName + '.position',\n\t\t\t\t\t\tanimationKeys, 'pos', tracks );\n\n\t\t\t\taddNonemptyTrack(\n\t\t\t\t\t\tQuaternionKeyframeTrack, boneName + '.quaternion',\n\t\t\t\t\t\tanimationKeys, 'rot', tracks );\n\n\t\t\t\taddNonemptyTrack(\n\t\t\t\t\t\tVectorKeyframeTrack, boneName + '.scale',\n\t\t\t\t\t\tanimationKeys, 'scl', tracks );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( tracks.length === 0 ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\tvar clip = new AnimationClip( clipName, duration, tracks );\n\n\t\treturn clip;\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction MaterialLoader( manager ) {\n\n\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\tthis.textures = {};\n\n}\n\nObject.assign( MaterialLoader.prototype, {\n\n\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\tvar scope = this;\n\n\t\tvar loader = new FileLoader( scope.manager );\n\t\tloader.load( url, function ( text ) {\n\n\t\t\tonLoad( scope.parse( JSON.parse( text ) ) );\n\n\t\t}, onProgress, onError );\n\n\t},\n\n\tsetTextures: function ( value ) {\n\n\t\tthis.textures = value;\n\n\t},\n\n\tparse: function ( json ) {\n\n\t\tvar textures = this.textures;\n\n\t\tfunction getTexture( name ) {\n\n\t\t\tif ( textures[ name ] === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.MaterialLoader: Undefined texture', name );\n\n\t\t\t}\n\n\t\t\treturn textures[ name ];\n\n\t\t}\n\n\t\tvar material = new Materials[ json.type ]();\n\n\t\tif ( json.uuid !== undefined ) material.uuid = json.uuid;\n\t\tif ( json.name !== undefined ) material.name = json.name;\n\t\tif ( json.color !== undefined ) material.color.setHex( json.color );\n\t\tif ( json.roughness !== undefined ) material.roughness = json.roughness;\n\t\tif ( json.metalness !== undefined ) material.metalness = json.metalness;\n\t\tif ( json.emissive !== undefined ) material.emissive.setHex( json.emissive );\n\t\tif ( json.specular !== undefined ) material.specular.setHex( json.specular );\n\t\tif ( json.shininess !== undefined ) material.shininess = json.shininess;\n\t\tif ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat;\n\t\tif ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness;\n\t\tif ( json.uniforms !== undefined ) material.uniforms = json.uniforms;\n\t\tif ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;\n\t\tif ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;\n\t\tif ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors;\n\t\tif ( json.fog !== undefined ) material.fog = json.fog;\n\t\tif ( json.shading !== undefined ) material.shading = json.shading;\n\t\tif ( json.blending !== undefined ) material.blending = json.blending;\n\t\tif ( json.side !== undefined ) material.side = json.side;\n\t\tif ( json.opacity !== undefined ) material.opacity = json.opacity;\n\t\tif ( json.transparent !== undefined ) material.transparent = json.transparent;\n\t\tif ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest;\n\t\tif ( json.depthTest !== undefined ) material.depthTest = json.depthTest;\n\t\tif ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite;\n\t\tif ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite;\n\t\tif ( json.wireframe !== undefined ) material.wireframe = json.wireframe;\n\t\tif ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth;\n\t\tif ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap;\n\t\tif ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin;\n\t\tif ( json.skinning !== undefined ) material.skinning = json.skinning;\n\t\tif ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets;\n\n\t\t// for PointsMaterial\n\n\t\tif ( json.size !== undefined ) material.size = json.size;\n\t\tif ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation;\n\n\t\t// maps\n\n\t\tif ( json.map !== undefined ) material.map = getTexture( json.map );\n\n\t\tif ( json.alphaMap !== undefined ) {\n\n\t\t\tmaterial.alphaMap = getTexture( json.alphaMap );\n\t\t\tmaterial.transparent = true;\n\n\t\t}\n\n\t\tif ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap );\n\t\tif ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale;\n\n\t\tif ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap );\n\t\tif ( json.normalScale !== undefined ) {\n\n\t\t\tvar normalScale = json.normalScale;\n\n\t\t\tif ( Array.isArray( normalScale ) === false ) {\n\n\t\t\t\t// Blender exporter used to export a scalar. See #7459\n\n\t\t\t\tnormalScale = [ normalScale, normalScale ];\n\n\t\t\t}\n\n\t\t\tmaterial.normalScale = new Vector2().fromArray( normalScale );\n\n\t\t}\n\n\t\tif ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap );\n\t\tif ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale;\n\t\tif ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias;\n\n\t\tif ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap );\n\t\tif ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap );\n\n\t\tif ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap );\n\t\tif ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity;\n\n\t\tif ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap );\n\n\t\tif ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap );\n\n\t\tif ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity;\n\n\t\tif ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap );\n\t\tif ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity;\n\n\t\tif ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap );\n\t\tif ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity;\n\n\t\tif ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap );\n\n\t\t// MultiMaterial\n\n\t\tif ( json.materials !== undefined ) {\n\n\t\t\tfor ( var i = 0, l = json.materials.length; i < l; i ++ ) {\n\n\t\t\t\tmaterial.materials.push( this.parse( json.materials[ i ] ) );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn material;\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction BufferGeometryLoader( manager ) {\n\n\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n}\n\nObject.assign( BufferGeometryLoader.prototype, {\n\n\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\tvar scope = this;\n\n\t\tvar loader = new FileLoader( scope.manager );\n\t\tloader.load( url, function ( text ) {\n\n\t\t\tonLoad( scope.parse( JSON.parse( text ) ) );\n\n\t\t}, onProgress, onError );\n\n\t},\n\n\tparse: function ( json ) {\n\n\t\tvar geometry = new BufferGeometry();\n\n\t\tvar index = json.data.index;\n\n\t\tvar TYPED_ARRAYS = {\n\t\t\t'Int8Array': Int8Array,\n\t\t\t'Uint8Array': Uint8Array,\n\t\t\t'Uint8ClampedArray': Uint8ClampedArray,\n\t\t\t'Int16Array': Int16Array,\n\t\t\t'Uint16Array': Uint16Array,\n\t\t\t'Int32Array': Int32Array,\n\t\t\t'Uint32Array': Uint32Array,\n\t\t\t'Float32Array': Float32Array,\n\t\t\t'Float64Array': Float64Array\n\t\t};\n\n\t\tif ( index !== undefined ) {\n\n\t\t\tvar typedArray = new TYPED_ARRAYS[ index.type ]( index.array );\n\t\t\tgeometry.setIndex( new BufferAttribute( typedArray, 1 ) );\n\n\t\t}\n\n\t\tvar attributes = json.data.attributes;\n\n\t\tfor ( var key in attributes ) {\n\n\t\t\tvar attribute = attributes[ key ];\n\t\t\tvar typedArray = new TYPED_ARRAYS[ attribute.type ]( attribute.array );\n\n\t\t\tgeometry.addAttribute( key, new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ) );\n\n\t\t}\n\n\t\tvar groups = json.data.groups || json.data.drawcalls || json.data.offsets;\n\n\t\tif ( groups !== undefined ) {\n\n\t\t\tfor ( var i = 0, n = groups.length; i !== n; ++ i ) {\n\n\t\t\t\tvar group = groups[ i ];\n\n\t\t\t\tgeometry.addGroup( group.start, group.count, group.materialIndex );\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar boundingSphere = json.data.boundingSphere;\n\n\t\tif ( boundingSphere !== undefined ) {\n\n\t\t\tvar center = new Vector3();\n\n\t\t\tif ( boundingSphere.center !== undefined ) {\n\n\t\t\t\tcenter.fromArray( boundingSphere.center );\n\n\t\t\t}\n\n\t\t\tgeometry.boundingSphere = new Sphere( center, boundingSphere.radius );\n\n\t\t}\n\n\t\treturn geometry;\n\n\t}\n\n} );\n\n/**\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction Loader() {\n\n\tthis.onLoadStart = function () {};\n\tthis.onLoadProgress = function () {};\n\tthis.onLoadComplete = function () {};\n\n}\n\nLoader.prototype = {\n\n\tconstructor: Loader,\n\n\tcrossOrigin: undefined,\n\n\textractUrlBase: function ( url ) {\n\n\t\tvar parts = url.split( '/' );\n\n\t\tif ( parts.length === 1 ) return './';\n\n\t\tparts.pop();\n\n\t\treturn parts.join( '/' ) + '/';\n\n\t},\n\n\tinitMaterials: function ( materials, texturePath, crossOrigin ) {\n\n\t\tvar array = [];\n\n\t\tfor ( var i = 0; i < materials.length; ++ i ) {\n\n\t\t\tarray[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin );\n\n\t\t}\n\n\t\treturn array;\n\n\t},\n\n\tcreateMaterial: ( function () {\n\n\t\tvar BlendingMode = {\n\t\t\tNoBlending: NoBlending,\n\t\t\tNormalBlending: NormalBlending,\n\t\t\tAdditiveBlending: AdditiveBlending,\n\t\t\tSubtractiveBlending: SubtractiveBlending,\n\t\t\tMultiplyBlending: MultiplyBlending,\n\t\t\tCustomBlending: CustomBlending\n\t\t};\n\n\t\tvar color, textureLoader, materialLoader;\n\n\t\treturn function createMaterial( m, texturePath, crossOrigin ) {\n\n\t\t\tif ( color === undefined ) color = new Color();\n\t\t\tif ( textureLoader === undefined ) textureLoader = new TextureLoader();\n\t\t\tif ( materialLoader === undefined ) materialLoader = new MaterialLoader();\n\n\t\t\t// convert from old material format\n\n\t\t\tvar textures = {};\n\n\t\t\tfunction loadTexture( path, repeat, offset, wrap, anisotropy ) {\n\n\t\t\t\tvar fullPath = texturePath + path;\n\t\t\t\tvar loader = Loader.Handlers.get( fullPath );\n\n\t\t\t\tvar texture;\n\n\t\t\t\tif ( loader !== null ) {\n\n\t\t\t\t\ttexture = loader.load( fullPath );\n\n\t\t\t\t} else {\n\n\t\t\t\t\ttextureLoader.setCrossOrigin( crossOrigin );\n\t\t\t\t\ttexture = textureLoader.load( fullPath );\n\n\t\t\t\t}\n\n\t\t\t\tif ( repeat !== undefined ) {\n\n\t\t\t\t\ttexture.repeat.fromArray( repeat );\n\n\t\t\t\t\tif ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping;\n\t\t\t\t\tif ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping;\n\n\t\t\t\t}\n\n\t\t\t\tif ( offset !== undefined ) {\n\n\t\t\t\t\ttexture.offset.fromArray( offset );\n\n\t\t\t\t}\n\n\t\t\t\tif ( wrap !== undefined ) {\n\n\t\t\t\t\tif ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping;\n\t\t\t\t\tif ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping;\n\n\t\t\t\t\tif ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping;\n\t\t\t\t\tif ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping;\n\n\t\t\t\t}\n\n\t\t\t\tif ( anisotropy !== undefined ) {\n\n\t\t\t\t\ttexture.anisotropy = anisotropy;\n\n\t\t\t\t}\n\n\t\t\t\tvar uuid = _Math.generateUUID();\n\n\t\t\t\ttextures[ uuid ] = texture;\n\n\t\t\t\treturn uuid;\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tvar json = {\n\t\t\t\tuuid: _Math.generateUUID(),\n\t\t\t\ttype: 'MeshLambertMaterial'\n\t\t\t};\n\n\t\t\tfor ( var name in m ) {\n\n\t\t\t\tvar value = m[ name ];\n\n\t\t\t\tswitch ( name ) {\n\n\t\t\t\t\tcase 'DbgColor':\n\t\t\t\t\tcase 'DbgIndex':\n\t\t\t\t\tcase 'opticalDensity':\n\t\t\t\t\tcase 'illumination':\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'DbgName':\n\t\t\t\t\t\tjson.name = value;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'blending':\n\t\t\t\t\t\tjson.blending = BlendingMode[ value ];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'colorAmbient':\n\t\t\t\t\tcase 'mapAmbient':\n\t\t\t\t\t\tconsole.warn( 'THREE.Loader.createMaterial:', name, 'is no longer supported.' );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'colorDiffuse':\n\t\t\t\t\t\tjson.color = color.fromArray( value ).getHex();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'colorSpecular':\n\t\t\t\t\t\tjson.specular = color.fromArray( value ).getHex();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'colorEmissive':\n\t\t\t\t\t\tjson.emissive = color.fromArray( value ).getHex();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'specularCoef':\n\t\t\t\t\t\tjson.shininess = value;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'shading':\n\t\t\t\t\t\tif ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial';\n\t\t\t\t\t\tif ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial';\n\t\t\t\t\t\tif ( value.toLowerCase() === 'standard' ) json.type = 'MeshStandardMaterial';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapDiffuse':\n\t\t\t\t\t\tjson.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapDiffuseRepeat':\n\t\t\t\t\tcase 'mapDiffuseOffset':\n\t\t\t\t\tcase 'mapDiffuseWrap':\n\t\t\t\t\tcase 'mapDiffuseAnisotropy':\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapEmissive':\n\t\t\t\t\t\tjson.emissiveMap = loadTexture( value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapEmissiveRepeat':\n\t\t\t\t\tcase 'mapEmissiveOffset':\n\t\t\t\t\tcase 'mapEmissiveWrap':\n\t\t\t\t\tcase 'mapEmissiveAnisotropy':\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapLight':\n\t\t\t\t\t\tjson.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapLightRepeat':\n\t\t\t\t\tcase 'mapLightOffset':\n\t\t\t\t\tcase 'mapLightWrap':\n\t\t\t\t\tcase 'mapLightAnisotropy':\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapAO':\n\t\t\t\t\t\tjson.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapAORepeat':\n\t\t\t\t\tcase 'mapAOOffset':\n\t\t\t\t\tcase 'mapAOWrap':\n\t\t\t\t\tcase 'mapAOAnisotropy':\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapBump':\n\t\t\t\t\t\tjson.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapBumpScale':\n\t\t\t\t\t\tjson.bumpScale = value;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapBumpRepeat':\n\t\t\t\t\tcase 'mapBumpOffset':\n\t\t\t\t\tcase 'mapBumpWrap':\n\t\t\t\t\tcase 'mapBumpAnisotropy':\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapNormal':\n\t\t\t\t\t\tjson.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapNormalFactor':\n\t\t\t\t\t\tjson.normalScale = [ value, value ];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapNormalRepeat':\n\t\t\t\t\tcase 'mapNormalOffset':\n\t\t\t\t\tcase 'mapNormalWrap':\n\t\t\t\t\tcase 'mapNormalAnisotropy':\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapSpecular':\n\t\t\t\t\t\tjson.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapSpecularRepeat':\n\t\t\t\t\tcase 'mapSpecularOffset':\n\t\t\t\t\tcase 'mapSpecularWrap':\n\t\t\t\t\tcase 'mapSpecularAnisotropy':\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapMetalness':\n\t\t\t\t\t\tjson.metalnessMap = loadTexture( value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapMetalnessRepeat':\n\t\t\t\t\tcase 'mapMetalnessOffset':\n\t\t\t\t\tcase 'mapMetalnessWrap':\n\t\t\t\t\tcase 'mapMetalnessAnisotropy':\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapRoughness':\n\t\t\t\t\t\tjson.roughnessMap = loadTexture( value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapRoughnessRepeat':\n\t\t\t\t\tcase 'mapRoughnessOffset':\n\t\t\t\t\tcase 'mapRoughnessWrap':\n\t\t\t\t\tcase 'mapRoughnessAnisotropy':\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapAlpha':\n\t\t\t\t\t\tjson.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'mapAlphaRepeat':\n\t\t\t\t\tcase 'mapAlphaOffset':\n\t\t\t\t\tcase 'mapAlphaWrap':\n\t\t\t\t\tcase 'mapAlphaAnisotropy':\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'flipSided':\n\t\t\t\t\t\tjson.side = BackSide;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'doubleSided':\n\t\t\t\t\t\tjson.side = DoubleSide;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'transparency':\n\t\t\t\t\t\tconsole.warn( 'THREE.Loader.createMaterial: transparency has been renamed to opacity' );\n\t\t\t\t\t\tjson.opacity = value;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'depthTest':\n\t\t\t\t\tcase 'depthWrite':\n\t\t\t\t\tcase 'colorWrite':\n\t\t\t\t\tcase 'opacity':\n\t\t\t\t\tcase 'reflectivity':\n\t\t\t\t\tcase 'transparent':\n\t\t\t\t\tcase 'visible':\n\t\t\t\t\tcase 'wireframe':\n\t\t\t\t\t\tjson[ name ] = value;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'vertexColors':\n\t\t\t\t\t\tif ( value === true ) json.vertexColors = VertexColors;\n\t\t\t\t\t\tif ( value === 'face' ) json.vertexColors = FaceColors;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tconsole.error( 'THREE.Loader.createMaterial: Unsupported', name, value );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( json.type === 'MeshBasicMaterial' ) delete json.emissive;\n\t\t\tif ( json.type !== 'MeshPhongMaterial' ) delete json.specular;\n\n\t\t\tif ( json.opacity < 1 ) json.transparent = true;\n\n\t\t\tmaterialLoader.setTextures( textures );\n\n\t\t\treturn materialLoader.parse( json );\n\n\t\t};\n\n\t} )()\n\n};\n\nLoader.Handlers = {\n\n\thandlers: [],\n\n\tadd: function ( regex, loader ) {\n\n\t\tthis.handlers.push( regex, loader );\n\n\t},\n\n\tget: function ( file ) {\n\n\t\tvar handlers = this.handlers;\n\n\t\tfor ( var i = 0, l = handlers.length; i < l; i += 2 ) {\n\n\t\t\tvar regex = handlers[ i ];\n\t\t\tvar loader = handlers[ i + 1 ];\n\n\t\t\tif ( regex.test( file ) ) {\n\n\t\t\t\treturn loader;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn null;\n\n\t}\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction JSONLoader( manager ) {\n\n\tif ( typeof manager === 'boolean' ) {\n\n\t\tconsole.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' );\n\t\tmanager = undefined;\n\n\t}\n\n\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n\tthis.withCredentials = false;\n\n}\n\nObject.assign( JSONLoader.prototype, {\n\n\tload: function( url, onLoad, onProgress, onError ) {\n\n\t\tvar scope = this;\n\n\t\tvar texturePath = this.texturePath && ( typeof this.texturePath === \"string\" ) ? this.texturePath : Loader.prototype.extractUrlBase( url );\n\n\t\tvar loader = new FileLoader( this.manager );\n\t\tloader.setWithCredentials( this.withCredentials );\n\t\tloader.load( url, function ( text ) {\n\n\t\t\tvar json = JSON.parse( text );\n\t\t\tvar metadata = json.metadata;\n\n\t\t\tif ( metadata !== undefined ) {\n\n\t\t\t\tvar type = metadata.type;\n\n\t\t\t\tif ( type !== undefined ) {\n\n\t\t\t\t\tif ( type.toLowerCase() === 'object' ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( type.toLowerCase() === 'scene' ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.SceneLoader instead.' );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tvar object = scope.parse( json, texturePath );\n\t\t\tonLoad( object.geometry, object.materials );\n\n\t\t}, onProgress, onError );\n\n\t},\n\n\tsetTexturePath: function ( value ) {\n\n\t\tthis.texturePath = value;\n\n\t},\n\n\tparse: function ( json, texturePath ) {\n\n\t\tvar geometry = new Geometry(),\n\t\tscale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0;\n\n\t\tparseModel( scale );\n\n\t\tparseSkin();\n\t\tparseMorphing( scale );\n\t\tparseAnimations();\n\n\t\tgeometry.computeFaceNormals();\n\t\tgeometry.computeBoundingSphere();\n\n\t\tfunction parseModel( scale ) {\n\n\t\t\tfunction isBitSet( value, position ) {\n\n\t\t\t\treturn value & ( 1 << position );\n\n\t\t\t}\n\n\t\t\tvar i, j, fi,\n\n\t\t\toffset, zLength,\n\n\t\tcolorIndex, normalIndex, uvIndex, materialIndex,\n\n\t\t\ttype,\n\t\t\tisQuad,\n\t\t\thasMaterial,\n\t\t\thasFaceVertexUv,\n\t\t\thasFaceNormal, hasFaceVertexNormal,\n\t\t\thasFaceColor, hasFaceVertexColor,\n\n\t\tvertex, face, faceA, faceB, hex, normal,\n\n\t\t\tuvLayer, uv, u, v,\n\n\t\t\tfaces = json.faces,\n\t\t\tvertices = json.vertices,\n\t\t\tnormals = json.normals,\n\t\t\tcolors = json.colors,\n\n\t\t\tnUvLayers = 0;\n\n\t\t\tif ( json.uvs !== undefined ) {\n\n\t\t\t\t// disregard empty arrays\n\n\t\t\t\tfor ( i = 0; i < json.uvs.length; i ++ ) {\n\n\t\t\t\t\tif ( json.uvs[ i ].length ) nUvLayers ++;\n\n\t\t\t\t}\n\n\t\t\t\tfor ( i = 0; i < nUvLayers; i ++ ) {\n\n\t\t\t\t\tgeometry.faceVertexUvs[ i ] = [];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\toffset = 0;\n\t\t\tzLength = vertices.length;\n\n\t\t\twhile ( offset < zLength ) {\n\n\t\t\t\tvertex = new Vector3();\n\n\t\t\t\tvertex.x = vertices[ offset ++ ] * scale;\n\t\t\t\tvertex.y = vertices[ offset ++ ] * scale;\n\t\t\t\tvertex.z = vertices[ offset ++ ] * scale;\n\n\t\t\t\tgeometry.vertices.push( vertex );\n\n\t\t\t}\n\n\t\t\toffset = 0;\n\t\t\tzLength = faces.length;\n\n\t\t\twhile ( offset < zLength ) {\n\n\t\t\t\ttype = faces[ offset ++ ];\n\n\n\t\t\t\tisQuad = isBitSet( type, 0 );\n\t\t\t\thasMaterial = isBitSet( type, 1 );\n\t\t\t\thasFaceVertexUv = isBitSet( type, 3 );\n\t\t\t\thasFaceNormal = isBitSet( type, 4 );\n\t\t\t\thasFaceVertexNormal = isBitSet( type, 5 );\n\t\t\t\thasFaceColor\t = isBitSet( type, 6 );\n\t\t\t\thasFaceVertexColor = isBitSet( type, 7 );\n\n\t\t\t\t// console.log(\"type\", type, \"bits\", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);\n\n\t\t\t\tif ( isQuad ) {\n\n\t\t\t\t\tfaceA = new Face3();\n\t\t\t\t\tfaceA.a = faces[ offset ];\n\t\t\t\t\tfaceA.b = faces[ offset + 1 ];\n\t\t\t\t\tfaceA.c = faces[ offset + 3 ];\n\n\t\t\t\t\tfaceB = new Face3();\n\t\t\t\t\tfaceB.a = faces[ offset + 1 ];\n\t\t\t\t\tfaceB.b = faces[ offset + 2 ];\n\t\t\t\t\tfaceB.c = faces[ offset + 3 ];\n\n\t\t\t\t\toffset += 4;\n\n\t\t\t\t\tif ( hasMaterial ) {\n\n\t\t\t\t\t\tmaterialIndex = faces[ offset ++ ];\n\t\t\t\t\t\tfaceA.materialIndex = materialIndex;\n\t\t\t\t\t\tfaceB.materialIndex = materialIndex;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// to get face <=> uv index correspondence\n\n\t\t\t\t\tfi = geometry.faces.length;\n\n\t\t\t\t\tif ( hasFaceVertexUv ) {\n\n\t\t\t\t\t\tfor ( i = 0; i < nUvLayers; i ++ ) {\n\n\t\t\t\t\t\t\tuvLayer = json.uvs[ i ];\n\n\t\t\t\t\t\t\tgeometry.faceVertexUvs[ i ][ fi ] = [];\n\t\t\t\t\t\t\tgeometry.faceVertexUvs[ i ][ fi + 1 ] = [];\n\n\t\t\t\t\t\t\tfor ( j = 0; j < 4; j ++ ) {\n\n\t\t\t\t\t\t\t\tuvIndex = faces[ offset ++ ];\n\n\t\t\t\t\t\t\t\tu = uvLayer[ uvIndex * 2 ];\n\t\t\t\t\t\t\t\tv = uvLayer[ uvIndex * 2 + 1 ];\n\n\t\t\t\t\t\t\t\tuv = new Vector2( u, v );\n\n\t\t\t\t\t\t\t\tif ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv );\n\t\t\t\t\t\t\t\tif ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( hasFaceNormal ) {\n\n\t\t\t\t\t\tnormalIndex = faces[ offset ++ ] * 3;\n\n\t\t\t\t\t\tfaceA.normal.set(\n\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\n\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\n\t\t\t\t\t\t\tnormals[ normalIndex ]\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tfaceB.normal.copy( faceA.normal );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( hasFaceVertexNormal ) {\n\n\t\t\t\t\t\tfor ( i = 0; i < 4; i ++ ) {\n\n\t\t\t\t\t\t\tnormalIndex = faces[ offset ++ ] * 3;\n\n\t\t\t\t\t\t\tnormal = new Vector3(\n\t\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\n\t\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\n\t\t\t\t\t\t\t\tnormals[ normalIndex ]\n\t\t\t\t\t\t\t);\n\n\n\t\t\t\t\t\t\tif ( i !== 2 ) faceA.vertexNormals.push( normal );\n\t\t\t\t\t\t\tif ( i !== 0 ) faceB.vertexNormals.push( normal );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\n\t\t\t\t\tif ( hasFaceColor ) {\n\n\t\t\t\t\t\tcolorIndex = faces[ offset ++ ];\n\t\t\t\t\t\thex = colors[ colorIndex ];\n\n\t\t\t\t\t\tfaceA.color.setHex( hex );\n\t\t\t\t\t\tfaceB.color.setHex( hex );\n\n\t\t\t\t\t}\n\n\n\t\t\t\t\tif ( hasFaceVertexColor ) {\n\n\t\t\t\t\t\tfor ( i = 0; i < 4; i ++ ) {\n\n\t\t\t\t\t\t\tcolorIndex = faces[ offset ++ ];\n\t\t\t\t\t\t\thex = colors[ colorIndex ];\n\n\t\t\t\t\t\t\tif ( i !== 2 ) faceA.vertexColors.push( new Color( hex ) );\n\t\t\t\t\t\t\tif ( i !== 0 ) faceB.vertexColors.push( new Color( hex ) );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tgeometry.faces.push( faceA );\n\t\t\t\t\tgeometry.faces.push( faceB );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tface = new Face3();\n\t\t\t\t\tface.a = faces[ offset ++ ];\n\t\t\t\t\tface.b = faces[ offset ++ ];\n\t\t\t\t\tface.c = faces[ offset ++ ];\n\n\t\t\t\t\tif ( hasMaterial ) {\n\n\t\t\t\t\t\tmaterialIndex = faces[ offset ++ ];\n\t\t\t\t\t\tface.materialIndex = materialIndex;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// to get face <=> uv index correspondence\n\n\t\t\t\t\tfi = geometry.faces.length;\n\n\t\t\t\t\tif ( hasFaceVertexUv ) {\n\n\t\t\t\t\t\tfor ( i = 0; i < nUvLayers; i ++ ) {\n\n\t\t\t\t\t\t\tuvLayer = json.uvs[ i ];\n\n\t\t\t\t\t\t\tgeometry.faceVertexUvs[ i ][ fi ] = [];\n\n\t\t\t\t\t\t\tfor ( j = 0; j < 3; j ++ ) {\n\n\t\t\t\t\t\t\t\tuvIndex = faces[ offset ++ ];\n\n\t\t\t\t\t\t\t\tu = uvLayer[ uvIndex * 2 ];\n\t\t\t\t\t\t\t\tv = uvLayer[ uvIndex * 2 + 1 ];\n\n\t\t\t\t\t\t\t\tuv = new Vector2( u, v );\n\n\t\t\t\t\t\t\t\tgeometry.faceVertexUvs[ i ][ fi ].push( uv );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( hasFaceNormal ) {\n\n\t\t\t\t\t\tnormalIndex = faces[ offset ++ ] * 3;\n\n\t\t\t\t\t\tface.normal.set(\n\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\n\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\n\t\t\t\t\t\t\tnormals[ normalIndex ]\n\t\t\t\t\t\t);\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( hasFaceVertexNormal ) {\n\n\t\t\t\t\t\tfor ( i = 0; i < 3; i ++ ) {\n\n\t\t\t\t\t\t\tnormalIndex = faces[ offset ++ ] * 3;\n\n\t\t\t\t\t\t\tnormal = new Vector3(\n\t\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\n\t\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\n\t\t\t\t\t\t\t\tnormals[ normalIndex ]\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tface.vertexNormals.push( normal );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\n\t\t\t\t\tif ( hasFaceColor ) {\n\n\t\t\t\t\t\tcolorIndex = faces[ offset ++ ];\n\t\t\t\t\t\tface.color.setHex( colors[ colorIndex ] );\n\n\t\t\t\t\t}\n\n\n\t\t\t\t\tif ( hasFaceVertexColor ) {\n\n\t\t\t\t\t\tfor ( i = 0; i < 3; i ++ ) {\n\n\t\t\t\t\t\t\tcolorIndex = faces[ offset ++ ];\n\t\t\t\t\t\t\tface.vertexColors.push( new Color( colors[ colorIndex ] ) );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tgeometry.faces.push( face );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction parseSkin() {\n\n\t\t\tvar influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2;\n\n\t\t\tif ( json.skinWeights ) {\n\n\t\t\t\tfor ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) {\n\n\t\t\t\t\tvar x = json.skinWeights[ i ];\n\t\t\t\t\tvar y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0;\n\t\t\t\t\tvar z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0;\n\t\t\t\t\tvar w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0;\n\n\t\t\t\t\tgeometry.skinWeights.push( new Vector4( x, y, z, w ) );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( json.skinIndices ) {\n\n\t\t\t\tfor ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) {\n\n\t\t\t\t\tvar a = json.skinIndices[ i ];\n\t\t\t\t\tvar b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0;\n\t\t\t\t\tvar c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0;\n\t\t\t\t\tvar d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0;\n\n\t\t\t\t\tgeometry.skinIndices.push( new Vector4( a, b, c, d ) );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tgeometry.bones = json.bones;\n\n\t\t\tif ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) {\n\n\t\t\t\tconsole.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' +\n\t\t\t\t\tgeometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction parseMorphing( scale ) {\n\n\t\t\tif ( json.morphTargets !== undefined ) {\n\n\t\t\t\tfor ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) {\n\n\t\t\t\t\tgeometry.morphTargets[ i ] = {};\n\t\t\t\t\tgeometry.morphTargets[ i ].name = json.morphTargets[ i ].name;\n\t\t\t\t\tgeometry.morphTargets[ i ].vertices = [];\n\n\t\t\t\t\tvar dstVertices = geometry.morphTargets[ i ].vertices;\n\t\t\t\t\tvar srcVertices = json.morphTargets[ i ].vertices;\n\n\t\t\t\t\tfor ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) {\n\n\t\t\t\t\t\tvar vertex = new Vector3();\n\t\t\t\t\t\tvertex.x = srcVertices[ v ] * scale;\n\t\t\t\t\t\tvertex.y = srcVertices[ v + 1 ] * scale;\n\t\t\t\t\t\tvertex.z = srcVertices[ v + 2 ] * scale;\n\n\t\t\t\t\t\tdstVertices.push( vertex );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( json.morphColors !== undefined && json.morphColors.length > 0 ) {\n\n\t\t\t\tconsole.warn( 'THREE.JSONLoader: \"morphColors\" no longer supported. Using them as face colors.' );\n\n\t\t\t\tvar faces = geometry.faces;\n\t\t\t\tvar morphColors = json.morphColors[ 0 ].colors;\n\n\t\t\t\tfor ( var i = 0, l = faces.length; i < l; i ++ ) {\n\n\t\t\t\t\tfaces[ i ].color.fromArray( morphColors, i * 3 );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction parseAnimations() {\n\n\t\t\tvar outputAnimations = [];\n\n\t\t\t// parse old style Bone/Hierarchy animations\n\t\t\tvar animations = [];\n\n\t\t\tif ( json.animation !== undefined ) {\n\n\t\t\t\tanimations.push( json.animation );\n\n\t\t\t}\n\n\t\t\tif ( json.animations !== undefined ) {\n\n\t\t\t\tif ( json.animations.length ) {\n\n\t\t\t\t\tanimations = animations.concat( json.animations );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tanimations.push( json.animations );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tfor ( var i = 0; i < animations.length; i ++ ) {\n\n\t\t\t\tvar clip = AnimationClip.parseAnimation( animations[ i ], geometry.bones );\n\t\t\t\tif ( clip ) outputAnimations.push( clip );\n\n\t\t\t}\n\n\t\t\t// parse implicit morph animations\n\t\t\tif ( geometry.morphTargets ) {\n\n\t\t\t\t// TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary.\n\t\t\t\tvar morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 );\n\t\t\t\toutputAnimations = outputAnimations.concat( morphAnimationClips );\n\n\t\t\t}\n\n\t\t\tif ( outputAnimations.length > 0 ) geometry.animations = outputAnimations;\n\n\t\t}\n\n\t\tif ( json.materials === undefined || json.materials.length === 0 ) {\n\n\t\t\treturn { geometry: geometry };\n\n\t\t} else {\n\n\t\t\tvar materials = Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin );\n\n\t\t\treturn { geometry: geometry, materials: materials };\n\n\t\t}\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction ObjectLoader( manager ) {\n\n\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\tthis.texturePath = '';\n\n}\n\nObject.assign( ObjectLoader.prototype, {\n\n\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\tif ( this.texturePath === '' ) {\n\n\t\t\tthis.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 );\n\n\t\t}\n\n\t\tvar scope = this;\n\n\t\tvar loader = new FileLoader( scope.manager );\n\t\tloader.load( url, function ( text ) {\n\n\t\t\tvar json = null;\n\n\t\t\ttry {\n\n\t\t\t\tjson = JSON.parse( text );\n\n\t\t\t} catch ( error ) {\n\n\t\t\t\tif ( onError !== undefined ) onError( error );\n\n\t\t\t\tconsole.error( 'THREE:ObjectLoader: Can\\'t parse ' + url + '.', error.message );\n\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tvar metadata = json.metadata;\n\n\t\t\tif ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {\n\n\t\t\t\tconsole.error( 'THREE.ObjectLoader: Can\\'t load ' + url + '. Use THREE.JSONLoader instead.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tscope.parse( json, onLoad );\n\n\t\t}, onProgress, onError );\n\n\t},\n\n\tsetTexturePath: function ( value ) {\n\n\t\tthis.texturePath = value;\n\n\t},\n\n\tsetCrossOrigin: function ( value ) {\n\n\t\tthis.crossOrigin = value;\n\n\t},\n\n\tparse: function ( json, onLoad ) {\n\n\t\tvar geometries = this.parseGeometries( json.geometries );\n\n\t\tvar images = this.parseImages( json.images, function () {\n\n\t\t\tif ( onLoad !== undefined ) onLoad( object );\n\n\t\t} );\n\n\t\tvar textures = this.parseTextures( json.textures, images );\n\t\tvar materials = this.parseMaterials( json.materials, textures );\n\n\t\tvar object = this.parseObject( json.object, geometries, materials );\n\n\t\tif ( json.animations ) {\n\n\t\t\tobject.animations = this.parseAnimations( json.animations );\n\n\t\t}\n\n\t\tif ( json.images === undefined || json.images.length === 0 ) {\n\n\t\t\tif ( onLoad !== undefined ) onLoad( object );\n\n\t\t}\n\n\t\treturn object;\n\n\t},\n\n\tparseGeometries: function ( json ) {\n\n\t\tvar geometries = {};\n\n\t\tif ( json !== undefined ) {\n\n\t\t\tvar geometryLoader = new JSONLoader();\n\t\t\tvar bufferGeometryLoader = new BufferGeometryLoader();\n\n\t\t\tfor ( var i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\tvar geometry;\n\t\t\t\tvar data = json[ i ];\n\n\t\t\t\tswitch ( data.type ) {\n\n\t\t\t\t\tcase 'PlaneGeometry':\n\t\t\t\t\tcase 'PlaneBufferGeometry':\n\n\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\tdata.width,\n\t\t\t\t\t\t\tdata.height,\n\t\t\t\t\t\t\tdata.widthSegments,\n\t\t\t\t\t\t\tdata.heightSegments\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'BoxGeometry':\n\t\t\t\t\tcase 'BoxBufferGeometry':\n\t\t\t\t\tcase 'CubeGeometry': // backwards compatible\n\n\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\tdata.width,\n\t\t\t\t\t\t\tdata.height,\n\t\t\t\t\t\t\tdata.depth,\n\t\t\t\t\t\t\tdata.widthSegments,\n\t\t\t\t\t\t\tdata.heightSegments,\n\t\t\t\t\t\t\tdata.depthSegments\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'CircleGeometry':\n\t\t\t\t\tcase 'CircleBufferGeometry':\n\n\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\t\tdata.segments,\n\t\t\t\t\t\t\tdata.thetaStart,\n\t\t\t\t\t\t\tdata.thetaLength\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'CylinderGeometry':\n\t\t\t\t\tcase 'CylinderBufferGeometry':\n\n\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\tdata.radiusTop,\n\t\t\t\t\t\t\tdata.radiusBottom,\n\t\t\t\t\t\t\tdata.height,\n\t\t\t\t\t\t\tdata.radialSegments,\n\t\t\t\t\t\t\tdata.heightSegments,\n\t\t\t\t\t\t\tdata.openEnded,\n\t\t\t\t\t\t\tdata.thetaStart,\n\t\t\t\t\t\t\tdata.thetaLength\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'ConeGeometry':\n\t\t\t\t\tcase 'ConeBufferGeometry':\n\n\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\t\tdata.height,\n\t\t\t\t\t\t\tdata.radialSegments,\n\t\t\t\t\t\t\tdata.heightSegments,\n\t\t\t\t\t\t\tdata.openEnded,\n\t\t\t\t\t\t\tdata.thetaStart,\n\t\t\t\t\t\t\tdata.thetaLength\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'SphereGeometry':\n\t\t\t\t\tcase 'SphereBufferGeometry':\n\n\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\t\tdata.widthSegments,\n\t\t\t\t\t\t\tdata.heightSegments,\n\t\t\t\t\t\t\tdata.phiStart,\n\t\t\t\t\t\t\tdata.phiLength,\n\t\t\t\t\t\t\tdata.thetaStart,\n\t\t\t\t\t\t\tdata.thetaLength\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'DodecahedronGeometry':\n\t\t\t\t\tcase 'IcosahedronGeometry':\n\t\t\t\t\tcase 'OctahedronGeometry':\n\t\t\t\t\tcase 'TetrahedronGeometry':\n\n\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\t\tdata.detail\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'RingGeometry':\n\t\t\t\t\tcase 'RingBufferGeometry':\n\n\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\tdata.innerRadius,\n\t\t\t\t\t\t\tdata.outerRadius,\n\t\t\t\t\t\t\tdata.thetaSegments,\n\t\t\t\t\t\t\tdata.phiSegments,\n\t\t\t\t\t\t\tdata.thetaStart,\n\t\t\t\t\t\t\tdata.thetaLength\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'TorusGeometry':\n\t\t\t\t\tcase 'TorusBufferGeometry':\n\n\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\t\tdata.tube,\n\t\t\t\t\t\t\tdata.radialSegments,\n\t\t\t\t\t\t\tdata.tubularSegments,\n\t\t\t\t\t\t\tdata.arc\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'TorusKnotGeometry':\n\t\t\t\t\tcase 'TorusKnotBufferGeometry':\n\n\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\t\tdata.tube,\n\t\t\t\t\t\t\tdata.tubularSegments,\n\t\t\t\t\t\t\tdata.radialSegments,\n\t\t\t\t\t\t\tdata.p,\n\t\t\t\t\t\t\tdata.q\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'LatheGeometry':\n\t\t\t\t\tcase 'LatheBufferGeometry':\n\n\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\tdata.points,\n\t\t\t\t\t\t\tdata.segments,\n\t\t\t\t\t\t\tdata.phiStart,\n\t\t\t\t\t\t\tdata.phiLength\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'BufferGeometry':\n\n\t\t\t\t\t\tgeometry = bufferGeometryLoader.parse( data );\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'Geometry':\n\n\t\t\t\t\t\tgeometry = geometryLoader.parse( data.data, this.texturePath ).geometry;\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\n\t\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Unsupported geometry type \"' + data.type + '\"' );\n\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t}\n\n\t\t\t\tgeometry.uuid = data.uuid;\n\n\t\t\t\tif ( data.name !== undefined ) geometry.name = data.name;\n\n\t\t\t\tgeometries[ data.uuid ] = geometry;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn geometries;\n\n\t},\n\n\tparseMaterials: function ( json, textures ) {\n\n\t\tvar materials = {};\n\n\t\tif ( json !== undefined ) {\n\n\t\t\tvar loader = new MaterialLoader();\n\t\t\tloader.setTextures( textures );\n\n\t\t\tfor ( var i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\tvar material = loader.parse( json[ i ] );\n\t\t\t\tmaterials[ material.uuid ] = material;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn materials;\n\n\t},\n\n\tparseAnimations: function ( json ) {\n\n\t\tvar animations = [];\n\n\t\tfor ( var i = 0; i < json.length; i ++ ) {\n\n\t\t\tvar clip = AnimationClip.parse( json[ i ] );\n\n\t\t\tanimations.push( clip );\n\n\t\t}\n\n\t\treturn animations;\n\n\t},\n\n\tparseImages: function ( json, onLoad ) {\n\n\t\tvar scope = this;\n\t\tvar images = {};\n\n\t\tfunction loadImage( url ) {\n\n\t\t\tscope.manager.itemStart( url );\n\n\t\t\treturn loader.load( url, function () {\n\n\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t}, undefined, function () {\n\n\t\t\t\tscope.manager.itemError( url );\n\n\t\t\t} );\n\n\t\t}\n\n\t\tif ( json !== undefined && json.length > 0 ) {\n\n\t\t\tvar manager = new LoadingManager( onLoad );\n\n\t\t\tvar loader = new ImageLoader( manager );\n\t\t\tloader.setCrossOrigin( this.crossOrigin );\n\n\t\t\tfor ( var i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\tvar image = json[ i ];\n\t\t\t\tvar path = /^(\\/\\/)|([a-z]+:(\\/\\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url;\n\n\t\t\t\timages[ image.uuid ] = loadImage( path );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn images;\n\n\t},\n\n\tparseTextures: function ( json, images ) {\n\n\t\tvar TextureMapping = {\n\t\t\tUVMapping: UVMapping,\n\t\t\tCubeReflectionMapping: CubeReflectionMapping,\n\t\t\tCubeRefractionMapping: CubeRefractionMapping,\n\t\t\tEquirectangularReflectionMapping: EquirectangularReflectionMapping,\n\t\t\tEquirectangularRefractionMapping: EquirectangularRefractionMapping,\n\t\t\tSphericalReflectionMapping: SphericalReflectionMapping,\n\t\t\tCubeUVReflectionMapping: CubeUVReflectionMapping,\n\t\t\tCubeUVRefractionMapping: CubeUVRefractionMapping\n\t\t};\n\n\t\tvar TextureWrapping = {\n\t\t\tRepeatWrapping: RepeatWrapping,\n\t\t\tClampToEdgeWrapping: ClampToEdgeWrapping,\n\t\t\tMirroredRepeatWrapping: MirroredRepeatWrapping\n\t\t};\n\n\t\tvar TextureFilter = {\n\t\t\tNearestFilter: NearestFilter,\n\t\t\tNearestMipMapNearestFilter: NearestMipMapNearestFilter,\n\t\t\tNearestMipMapLinearFilter: NearestMipMapLinearFilter,\n\t\t\tLinearFilter: LinearFilter,\n\t\t\tLinearMipMapNearestFilter: LinearMipMapNearestFilter,\n\t\t\tLinearMipMapLinearFilter: LinearMipMapLinearFilter\n\t\t};\n\n\t\tfunction parseConstant( value, type ) {\n\n\t\t\tif ( typeof( value ) === 'number' ) return value;\n\n\t\t\tconsole.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value );\n\n\t\t\treturn type[ value ];\n\n\t\t}\n\n\t\tvar textures = {};\n\n\t\tif ( json !== undefined ) {\n\n\t\t\tfor ( var i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\tvar data = json[ i ];\n\n\t\t\t\tif ( data.image === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: No \"image\" specified for', data.uuid );\n\n\t\t\t\t}\n\n\t\t\t\tif ( images[ data.image ] === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Undefined image', data.image );\n\n\t\t\t\t}\n\n\t\t\t\tvar texture = new Texture( images[ data.image ] );\n\t\t\t\ttexture.needsUpdate = true;\n\n\t\t\t\ttexture.uuid = data.uuid;\n\n\t\t\t\tif ( data.name !== undefined ) texture.name = data.name;\n\n\t\t\t\tif ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TextureMapping );\n\n\t\t\t\tif ( data.offset !== undefined ) texture.offset.fromArray( data.offset );\n\t\t\t\tif ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat );\n\t\t\t\tif ( data.wrap !== undefined ) {\n\n\t\t\t\t\ttexture.wrapS = parseConstant( data.wrap[ 0 ], TextureWrapping );\n\t\t\t\t\ttexture.wrapT = parseConstant( data.wrap[ 1 ], TextureWrapping );\n\n\t\t\t\t}\n\n\t\t\t\tif ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TextureFilter );\n\t\t\t\tif ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TextureFilter );\n\t\t\t\tif ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy;\n\n\t\t\t\tif ( data.flipY !== undefined ) texture.flipY = data.flipY;\n\n\t\t\t\ttextures[ data.uuid ] = texture;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn textures;\n\n\t},\n\n\tparseObject: function () {\n\n\t\tvar matrix = new Matrix4();\n\n\t\treturn function parseObject( data, geometries, materials ) {\n\n\t\t\tvar object;\n\n\t\t\tfunction getGeometry( name ) {\n\n\t\t\t\tif ( geometries[ name ] === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Undefined geometry', name );\n\n\t\t\t\t}\n\n\t\t\t\treturn geometries[ name ];\n\n\t\t\t}\n\n\t\t\tfunction getMaterial( name ) {\n\n\t\t\t\tif ( name === undefined ) return undefined;\n\n\t\t\t\tif ( materials[ name ] === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Undefined material', name );\n\n\t\t\t\t}\n\n\t\t\t\treturn materials[ name ];\n\n\t\t\t}\n\n\t\t\tswitch ( data.type ) {\n\n\t\t\t\tcase 'Scene':\n\n\t\t\t\t\tobject = new Scene();\n\n\t\t\t\t\tif ( data.background !== undefined ) {\n\n\t\t\t\t\t\tif ( Number.isInteger( data.background ) ) {\n\n\t\t\t\t\t\t\tobject.background = new Color( data.background );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( data.fog !== undefined ) {\n\n\t\t\t\t\t\tif ( data.fog.type === 'Fog' ) {\n\n\t\t\t\t\t\t\tobject.fog = new Fog( data.fog.color, data.fog.near, data.fog.far );\n\n\t\t\t\t\t\t} else if ( data.fog.type === 'FogExp2' ) {\n\n\t\t\t\t\t\t\tobject.fog = new FogExp2( data.fog.color, data.fog.density );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'PerspectiveCamera':\n\n\t\t\t\t\tobject = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far );\n\n\t\t\t\t\tif ( data.focus !== undefined ) object.focus = data.focus;\n\t\t\t\t\tif ( data.zoom !== undefined ) object.zoom = data.zoom;\n\t\t\t\t\tif ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge;\n\t\t\t\t\tif ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset;\n\t\t\t\t\tif ( data.view !== undefined ) object.view = Object.assign( {}, data.view );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'OrthographicCamera':\n\n\t\t\t\t\tobject = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'AmbientLight':\n\n\t\t\t\t\tobject = new AmbientLight( data.color, data.intensity );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'DirectionalLight':\n\n\t\t\t\t\tobject = new DirectionalLight( data.color, data.intensity );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'PointLight':\n\n\t\t\t\t\tobject = new PointLight( data.color, data.intensity, data.distance, data.decay );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'SpotLight':\n\n\t\t\t\t\tobject = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'HemisphereLight':\n\n\t\t\t\t\tobject = new HemisphereLight( data.color, data.groundColor, data.intensity );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'Mesh':\n\n\t\t\t\t\tvar geometry = getGeometry( data.geometry );\n\t\t\t\t\tvar material = getMaterial( data.material );\n\n\t\t\t\t\tif ( geometry.bones && geometry.bones.length > 0 ) {\n\n\t\t\t\t\t\tobject = new SkinnedMesh( geometry, material );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tobject = new Mesh( geometry, material );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'LOD':\n\n\t\t\t\t\tobject = new LOD();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'Line':\n\n\t\t\t\t\tobject = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'LineSegments':\n\n\t\t\t\t\tobject = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'PointCloud':\n\t\t\t\tcase 'Points':\n\n\t\t\t\t\tobject = new Points( getGeometry( data.geometry ), getMaterial( data.material ) );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'Sprite':\n\n\t\t\t\t\tobject = new Sprite( getMaterial( data.material ) );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'Group':\n\n\t\t\t\t\tobject = new Group();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'SkinnedMesh':\n\n\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh type. Instantiates Object3D instead.' );\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tobject = new Object3D();\n\n\t\t\t}\n\n\t\t\tobject.uuid = data.uuid;\n\n\t\t\tif ( data.name !== undefined ) object.name = data.name;\n\t\t\tif ( data.matrix !== undefined ) {\n\n\t\t\t\tmatrix.fromArray( data.matrix );\n\t\t\t\tmatrix.decompose( object.position, object.quaternion, object.scale );\n\n\t\t\t} else {\n\n\t\t\t\tif ( data.position !== undefined ) object.position.fromArray( data.position );\n\t\t\t\tif ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation );\n\t\t\t\tif ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion );\n\t\t\t\tif ( data.scale !== undefined ) object.scale.fromArray( data.scale );\n\n\t\t\t}\n\n\t\t\tif ( data.castShadow !== undefined ) object.castShadow = data.castShadow;\n\t\t\tif ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow;\n\n\t\t\tif ( data.shadow ) {\n\n\t\t\t\tif ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias;\n\t\t\t\tif ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius;\n\t\t\t\tif ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize );\n\t\t\t\tif ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera );\n\n\t\t\t}\n\n\t\t\tif ( data.visible !== undefined ) object.visible = data.visible;\n\t\t\tif ( data.userData !== undefined ) object.userData = data.userData;\n\n\t\t\tif ( data.children !== undefined ) {\n\n\t\t\t\tfor ( var child in data.children ) {\n\n\t\t\t\t\tobject.add( this.parseObject( data.children[ child ], geometries, materials ) );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( data.type === 'LOD' ) {\n\n\t\t\t\tvar levels = data.levels;\n\n\t\t\t\tfor ( var l = 0; l < levels.length; l ++ ) {\n\n\t\t\t\t\tvar level = levels[ l ];\n\t\t\t\t\tvar child = object.getObjectByProperty( 'uuid', level.object );\n\n\t\t\t\t\tif ( child !== undefined ) {\n\n\t\t\t\t\t\tobject.addLevel( child, level.distance );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn object;\n\n\t\t};\n\n\t}()\n\n} );\n\n/**\n * @author zz85 / http://www.lab4games.net/zz85/blog\n *\n * Bezier Curves formulas obtained from\n * http://en.wikipedia.org/wiki/Bézier_curve\n */\n\nfunction CatmullRom( t, p0, p1, p2, p3 ) {\n\n\tvar v0 = ( p2 - p0 ) * 0.5;\n\tvar v1 = ( p3 - p1 ) * 0.5;\n\tvar t2 = t * t;\n\tvar t3 = t * t2;\n\treturn ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;\n\n}\n\n//\n\nfunction QuadraticBezierP0( t, p ) {\n\n\tvar k = 1 - t;\n\treturn k * k * p;\n\n}\n\nfunction QuadraticBezierP1( t, p ) {\n\n\treturn 2 * ( 1 - t ) * t * p;\n\n}\n\nfunction QuadraticBezierP2( t, p ) {\n\n\treturn t * t * p;\n\n}\n\nfunction QuadraticBezier( t, p0, p1, p2 ) {\n\n\treturn QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +\n\t\tQuadraticBezierP2( t, p2 );\n\n}\n\n//\n\nfunction CubicBezierP0( t, p ) {\n\n\tvar k = 1 - t;\n\treturn k * k * k * p;\n\n}\n\nfunction CubicBezierP1( t, p ) {\n\n\tvar k = 1 - t;\n\treturn 3 * k * k * t * p;\n\n}\n\nfunction CubicBezierP2( t, p ) {\n\n\treturn 3 * ( 1 - t ) * t * t * p;\n\n}\n\nfunction CubicBezierP3( t, p ) {\n\n\treturn t * t * t * p;\n\n}\n\nfunction CubicBezier( t, p0, p1, p2, p3 ) {\n\n\treturn CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +\n\t\tCubicBezierP3( t, p3 );\n\n}\n\n/**\n * @author zz85 / http://www.lab4games.net/zz85/blog\n * Extensible curve object\n *\n * Some common of Curve methods\n * .getPoint(t), getTangent(t)\n * .getPointAt(u), getTangentAt(u)\n * .getPoints(), .getSpacedPoints()\n * .getLength()\n * .updateArcLengths()\n *\n * This following classes subclasses THREE.Curve:\n *\n * -- 2d classes --\n * THREE.LineCurve\n * THREE.QuadraticBezierCurve\n * THREE.CubicBezierCurve\n * THREE.SplineCurve\n * THREE.ArcCurve\n * THREE.EllipseCurve\n *\n * -- 3d classes --\n * THREE.LineCurve3\n * THREE.QuadraticBezierCurve3\n * THREE.CubicBezierCurve3\n * THREE.CatmullRomCurve3\n *\n * A series of curves can be represented as a THREE.CurvePath\n *\n **/\n\n/**************************************************************\n *\tAbstract Curve base class\n **************************************************************/\n\nfunction Curve() {}\n\nCurve.prototype = {\n\n\tconstructor: Curve,\n\n\t// Virtual base class method to overwrite and implement in subclasses\n\t//\t- t [0 .. 1]\n\n\tgetPoint: function ( t ) {\n\n\t\tconsole.warn( \"THREE.Curve: Warning, getPoint() not implemented!\" );\n\t\treturn null;\n\n\t},\n\n\t// Get point at relative position in curve according to arc length\n\t// - u [0 .. 1]\n\n\tgetPointAt: function ( u ) {\n\n\t\tvar t = this.getUtoTmapping( u );\n\t\treturn this.getPoint( t );\n\n\t},\n\n\t// Get sequence of points using getPoint( t )\n\n\tgetPoints: function ( divisions ) {\n\n\t\tif ( isNaN( divisions ) ) divisions = 5;\n\n\t\tvar points = [];\n\n\t\tfor ( var d = 0; d <= divisions; d ++ ) {\n\n\t\t\tpoints.push( this.getPoint( d / divisions ) );\n\n\t\t}\n\n\t\treturn points;\n\n\t},\n\n\t// Get sequence of points using getPointAt( u )\n\n\tgetSpacedPoints: function ( divisions ) {\n\n\t\tif ( isNaN( divisions ) ) divisions = 5;\n\n\t\tvar points = [];\n\n\t\tfor ( var d = 0; d <= divisions; d ++ ) {\n\n\t\t\tpoints.push( this.getPointAt( d / divisions ) );\n\n\t\t}\n\n\t\treturn points;\n\n\t},\n\n\t// Get total curve arc length\n\n\tgetLength: function () {\n\n\t\tvar lengths = this.getLengths();\n\t\treturn lengths[ lengths.length - 1 ];\n\n\t},\n\n\t// Get list of cumulative segment lengths\n\n\tgetLengths: function ( divisions ) {\n\n\t\tif ( isNaN( divisions ) ) divisions = ( this.__arcLengthDivisions ) ? ( this.__arcLengthDivisions ) : 200;\n\n\t\tif ( this.cacheArcLengths\n\t\t\t&& ( this.cacheArcLengths.length === divisions + 1 )\n\t\t\t&& ! this.needsUpdate ) {\n\n\t\t\t//console.log( \"cached\", this.cacheArcLengths );\n\t\t\treturn this.cacheArcLengths;\n\n\t\t}\n\n\t\tthis.needsUpdate = false;\n\n\t\tvar cache = [];\n\t\tvar current, last = this.getPoint( 0 );\n\t\tvar p, sum = 0;\n\n\t\tcache.push( 0 );\n\n\t\tfor ( p = 1; p <= divisions; p ++ ) {\n\n\t\t\tcurrent = this.getPoint ( p / divisions );\n\t\t\tsum += current.distanceTo( last );\n\t\t\tcache.push( sum );\n\t\t\tlast = current;\n\n\t\t}\n\n\t\tthis.cacheArcLengths = cache;\n\n\t\treturn cache; // { sums: cache, sum:sum }; Sum is in the last element.\n\n\t},\n\n\tupdateArcLengths: function() {\n\n\t\tthis.needsUpdate = true;\n\t\tthis.getLengths();\n\n\t},\n\n\t// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant\n\n\tgetUtoTmapping: function ( u, distance ) {\n\n\t\tvar arcLengths = this.getLengths();\n\n\t\tvar i = 0, il = arcLengths.length;\n\n\t\tvar targetArcLength; // The targeted u distance value to get\n\n\t\tif ( distance ) {\n\n\t\t\ttargetArcLength = distance;\n\n\t\t} else {\n\n\t\t\ttargetArcLength = u * arcLengths[ il - 1 ];\n\n\t\t}\n\n\t\t//var time = Date.now();\n\n\t\t// binary search for the index with largest value smaller than target u distance\n\n\t\tvar low = 0, high = il - 1, comparison;\n\n\t\twhile ( low <= high ) {\n\n\t\t\ti = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats\n\n\t\t\tcomparison = arcLengths[ i ] - targetArcLength;\n\n\t\t\tif ( comparison < 0 ) {\n\n\t\t\t\tlow = i + 1;\n\n\t\t\t} else if ( comparison > 0 ) {\n\n\t\t\t\thigh = i - 1;\n\n\t\t\t} else {\n\n\t\t\t\thigh = i;\n\t\t\t\tbreak;\n\n\t\t\t\t// DONE\n\n\t\t\t}\n\n\t\t}\n\n\t\ti = high;\n\n\t\t//console.log('b' , i, low, high, Date.now()- time);\n\n\t\tif ( arcLengths[ i ] === targetArcLength ) {\n\n\t\t\tvar t = i / ( il - 1 );\n\t\t\treturn t;\n\n\t\t}\n\n\t\t// we could get finer grain at lengths, or use simple interpolation between two points\n\n\t\tvar lengthBefore = arcLengths[ i ];\n\t\tvar lengthAfter = arcLengths[ i + 1 ];\n\n\t\tvar segmentLength = lengthAfter - lengthBefore;\n\n\t\t// determine where we are between the 'before' and 'after' points\n\n\t\tvar segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;\n\n\t\t// add that fractional amount to t\n\n\t\tvar t = ( i + segmentFraction ) / ( il - 1 );\n\n\t\treturn t;\n\n\t},\n\n\t// Returns a unit vector tangent at t\n\t// In case any sub curve does not implement its tangent derivation,\n\t// 2 points a small delta apart will be used to find its gradient\n\t// which seems to give a reasonable approximation\n\n\tgetTangent: function( t ) {\n\n\t\tvar delta = 0.0001;\n\t\tvar t1 = t - delta;\n\t\tvar t2 = t + delta;\n\n\t\t// Capping in case of danger\n\n\t\tif ( t1 < 0 ) t1 = 0;\n\t\tif ( t2 > 1 ) t2 = 1;\n\n\t\tvar pt1 = this.getPoint( t1 );\n\t\tvar pt2 = this.getPoint( t2 );\n\n\t\tvar vec = pt2.clone().sub( pt1 );\n\t\treturn vec.normalize();\n\n\t},\n\n\tgetTangentAt: function ( u ) {\n\n\t\tvar t = this.getUtoTmapping( u );\n\t\treturn this.getTangent( t );\n\n\t},\n\n\tcomputeFrenetFrames: function ( segments, closed ) {\n\n\t\t// see http://www.cs.indiana.edu/pub/techreports/TR425.pdf\n\n\t\tvar normal = new Vector3();\n\n\t\tvar tangents = [];\n\t\tvar normals = [];\n\t\tvar binormals = [];\n\n\t\tvar vec = new Vector3();\n\t\tvar mat = new Matrix4();\n\n\t\tvar i, u, theta;\n\n\t\t// compute the tangent vectors for each segment on the curve\n\n\t\tfor ( i = 0; i <= segments; i ++ ) {\n\n\t\t\tu = i / segments;\n\n\t\t\ttangents[ i ] = this.getTangentAt( u );\n\t\t\ttangents[ i ].normalize();\n\n\t\t}\n\n\t\t// select an initial normal vector perpendicular to the first tangent vector,\n\t\t// and in the direction of the minimum tangent xyz component\n\n\t\tnormals[ 0 ] = new Vector3();\n\t\tbinormals[ 0 ] = new Vector3();\n\t\tvar min = Number.MAX_VALUE;\n\t\tvar tx = Math.abs( tangents[ 0 ].x );\n\t\tvar ty = Math.abs( tangents[ 0 ].y );\n\t\tvar tz = Math.abs( tangents[ 0 ].z );\n\n\t\tif ( tx <= min ) {\n\n\t\t\tmin = tx;\n\t\t\tnormal.set( 1, 0, 0 );\n\n\t\t}\n\n\t\tif ( ty <= min ) {\n\n\t\t\tmin = ty;\n\t\t\tnormal.set( 0, 1, 0 );\n\n\t\t}\n\n\t\tif ( tz <= min ) {\n\n\t\t\tnormal.set( 0, 0, 1 );\n\n\t\t}\n\n\t\tvec.crossVectors( tangents[ 0 ], normal ).normalize();\n\n\t\tnormals[ 0 ].crossVectors( tangents[ 0 ], vec );\n\t\tbinormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );\n\n\n\t\t// compute the slowly-varying normal and binormal vectors for each segment on the curve\n\n\t\tfor ( i = 1; i <= segments; i ++ ) {\n\n\t\t\tnormals[ i ] = normals[ i - 1 ].clone();\n\n\t\t\tbinormals[ i ] = binormals[ i - 1 ].clone();\n\n\t\t\tvec.crossVectors( tangents[ i - 1 ], tangents[ i ] );\n\n\t\t\tif ( vec.length() > Number.EPSILON ) {\n\n\t\t\t\tvec.normalize();\n\n\t\t\t\ttheta = Math.acos( _Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors\n\n\t\t\t\tnormals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );\n\n\t\t\t}\n\n\t\t\tbinormals[ i ].crossVectors( tangents[ i ], normals[ i ] );\n\n\t\t}\n\n\t\t// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same\n\n\t\tif ( closed === true ) {\n\n\t\t\ttheta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );\n\t\t\ttheta /= segments;\n\n\t\t\tif ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {\n\n\t\t\t\ttheta = - theta;\n\n\t\t\t}\n\n\t\t\tfor ( i = 1; i <= segments; i ++ ) {\n\n\t\t\t\t// twist a little...\n\t\t\t\tnormals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );\n\t\t\t\tbinormals[ i ].crossVectors( tangents[ i ], normals[ i ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn {\n\t\t\ttangents: tangents,\n\t\t\tnormals: normals,\n\t\t\tbinormals: binormals\n\t\t};\n\n\t}\n\n};\n\nfunction LineCurve( v1, v2 ) {\n\n\tthis.v1 = v1;\n\tthis.v2 = v2;\n\n}\n\nLineCurve.prototype = Object.create( Curve.prototype );\nLineCurve.prototype.constructor = LineCurve;\n\nLineCurve.prototype.isLineCurve = true;\n\nLineCurve.prototype.getPoint = function ( t ) {\n\n\tif ( t === 1 ) {\n\n\t\treturn this.v2.clone();\n\n\t}\n\n\tvar point = this.v2.clone().sub( this.v1 );\n\tpoint.multiplyScalar( t ).add( this.v1 );\n\n\treturn point;\n\n};\n\n// Line curve is linear, so we can overwrite default getPointAt\n\nLineCurve.prototype.getPointAt = function ( u ) {\n\n\treturn this.getPoint( u );\n\n};\n\nLineCurve.prototype.getTangent = function ( t ) {\n\n\tvar tangent = this.v2.clone().sub( this.v1 );\n\n\treturn tangent.normalize();\n\n};\n\n/**\n * @author zz85 / http://www.lab4games.net/zz85/blog\n *\n **/\n\n/**************************************************************\n *\tCurved Path - a curve path is simply a array of connected\n * curves, but retains the api of a curve\n **************************************************************/\n\nfunction CurvePath() {\n\n\tthis.curves = [];\n\n\tthis.autoClose = false; // Automatically closes the path\n\n}\n\nCurvePath.prototype = Object.assign( Object.create( Curve.prototype ), {\n\n\tconstructor: CurvePath,\n\n\tadd: function ( curve ) {\n\n\t\tthis.curves.push( curve );\n\n\t},\n\n\tclosePath: function () {\n\n\t\t// Add a line curve if start and end of lines are not connected\n\t\tvar startPoint = this.curves[ 0 ].getPoint( 0 );\n\t\tvar endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );\n\n\t\tif ( ! startPoint.equals( endPoint ) ) {\n\n\t\t\tthis.curves.push( new LineCurve( endPoint, startPoint ) );\n\n\t\t}\n\n\t},\n\n\t// To get accurate point with reference to\n\t// entire path distance at time t,\n\t// following has to be done:\n\n\t// 1. Length of each sub path have to be known\n\t// 2. Locate and identify type of curve\n\t// 3. Get t for the curve\n\t// 4. Return curve.getPointAt(t')\n\n\tgetPoint: function ( t ) {\n\n\t\tvar d = t * this.getLength();\n\t\tvar curveLengths = this.getCurveLengths();\n\t\tvar i = 0;\n\n\t\t// To think about boundaries points.\n\n\t\twhile ( i < curveLengths.length ) {\n\n\t\t\tif ( curveLengths[ i ] >= d ) {\n\n\t\t\t\tvar diff = curveLengths[ i ] - d;\n\t\t\t\tvar curve = this.curves[ i ];\n\n\t\t\t\tvar segmentLength = curve.getLength();\n\t\t\t\tvar u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;\n\n\t\t\t\treturn curve.getPointAt( u );\n\n\t\t\t}\n\n\t\t\ti ++;\n\n\t\t}\n\n\t\treturn null;\n\n\t\t// loop where sum != 0, sum > d , sum+1 1 && !points[ points.length - 1 ].equals( points[ 0 ] ) ) {\n\n\t\t\tpoints.push( points[ 0 ] );\n\n\t\t}\n\n\t\treturn points;\n\n\t},\n\n\t/**************************************************************\n\t *\tCreate Geometries Helpers\n\t **************************************************************/\n\n\t/// Generate geometry from path points (for Line or Points objects)\n\n\tcreatePointsGeometry: function ( divisions ) {\n\n\t\tvar pts = this.getPoints( divisions );\n\t\treturn this.createGeometry( pts );\n\n\t},\n\n\t// Generate geometry from equidistant sampling along the path\n\n\tcreateSpacedPointsGeometry: function ( divisions ) {\n\n\t\tvar pts = this.getSpacedPoints( divisions );\n\t\treturn this.createGeometry( pts );\n\n\t},\n\n\tcreateGeometry: function ( points ) {\n\n\t\tvar geometry = new Geometry();\n\n\t\tfor ( var i = 0, l = points.length; i < l; i ++ ) {\n\n\t\t\tvar point = points[ i ];\n\t\t\tgeometry.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) );\n\n\t\t}\n\n\t\treturn geometry;\n\n\t}\n\n} );\n\nfunction EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {\n\n\tthis.aX = aX;\n\tthis.aY = aY;\n\n\tthis.xRadius = xRadius;\n\tthis.yRadius = yRadius;\n\n\tthis.aStartAngle = aStartAngle;\n\tthis.aEndAngle = aEndAngle;\n\n\tthis.aClockwise = aClockwise;\n\n\tthis.aRotation = aRotation || 0;\n\n}\n\nEllipseCurve.prototype = Object.create( Curve.prototype );\nEllipseCurve.prototype.constructor = EllipseCurve;\n\nEllipseCurve.prototype.isEllipseCurve = true;\n\nEllipseCurve.prototype.getPoint = function ( t ) {\n\n\tvar twoPi = Math.PI * 2;\n\tvar deltaAngle = this.aEndAngle - this.aStartAngle;\n\tvar samePoints = Math.abs( deltaAngle ) < Number.EPSILON;\n\n\t// ensures that deltaAngle is 0 .. 2 PI\n\twhile ( deltaAngle < 0 ) deltaAngle += twoPi;\n\twhile ( deltaAngle > twoPi ) deltaAngle -= twoPi;\n\n\tif ( deltaAngle < Number.EPSILON ) {\n\n\t\tif ( samePoints ) {\n\n\t\t\tdeltaAngle = 0;\n\n\t\t} else {\n\n\t\t\tdeltaAngle = twoPi;\n\n\t\t}\n\n\t}\n\n\tif ( this.aClockwise === true && ! samePoints ) {\n\n\t\tif ( deltaAngle === twoPi ) {\n\n\t\t\tdeltaAngle = - twoPi;\n\n\t\t} else {\n\n\t\t\tdeltaAngle = deltaAngle - twoPi;\n\n\t\t}\n\n\t}\n\n\tvar angle = this.aStartAngle + t * deltaAngle;\n\tvar x = this.aX + this.xRadius * Math.cos( angle );\n\tvar y = this.aY + this.yRadius * Math.sin( angle );\n\n\tif ( this.aRotation !== 0 ) {\n\n\t\tvar cos = Math.cos( this.aRotation );\n\t\tvar sin = Math.sin( this.aRotation );\n\n\t\tvar tx = x - this.aX;\n\t\tvar ty = y - this.aY;\n\n\t\t// Rotate the point about the center of the ellipse.\n\t\tx = tx * cos - ty * sin + this.aX;\n\t\ty = tx * sin + ty * cos + this.aY;\n\n\t}\n\n\treturn new Vector2( x, y );\n\n};\n\nfunction SplineCurve( points /* array of Vector2 */ ) {\n\n\tthis.points = ( points === undefined ) ? [] : points;\n\n}\n\nSplineCurve.prototype = Object.create( Curve.prototype );\nSplineCurve.prototype.constructor = SplineCurve;\n\nSplineCurve.prototype.isSplineCurve = true;\n\nSplineCurve.prototype.getPoint = function ( t ) {\n\n\tvar points = this.points;\n\tvar point = ( points.length - 1 ) * t;\n\n\tvar intPoint = Math.floor( point );\n\tvar weight = point - intPoint;\n\n\tvar point0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ];\n\tvar point1 = points[ intPoint ];\n\tvar point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];\n\tvar point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];\n\n\treturn new Vector2(\n\t\tCatmullRom( weight, point0.x, point1.x, point2.x, point3.x ),\n\t\tCatmullRom( weight, point0.y, point1.y, point2.y, point3.y )\n\t);\n\n};\n\nfunction CubicBezierCurve( v0, v1, v2, v3 ) {\n\n\tthis.v0 = v0;\n\tthis.v1 = v1;\n\tthis.v2 = v2;\n\tthis.v3 = v3;\n\n}\n\nCubicBezierCurve.prototype = Object.create( Curve.prototype );\nCubicBezierCurve.prototype.constructor = CubicBezierCurve;\n\nCubicBezierCurve.prototype.getPoint = function ( t ) {\n\n\tvar v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;\n\n\treturn new Vector2(\n\t\tCubicBezier( t, v0.x, v1.x, v2.x, v3.x ),\n\t\tCubicBezier( t, v0.y, v1.y, v2.y, v3.y )\n\t);\n\n};\n\nfunction QuadraticBezierCurve( v0, v1, v2 ) {\n\n\tthis.v0 = v0;\n\tthis.v1 = v1;\n\tthis.v2 = v2;\n\n}\n\nQuadraticBezierCurve.prototype = Object.create( Curve.prototype );\nQuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve;\n\nQuadraticBezierCurve.prototype.getPoint = function ( t ) {\n\n\tvar v0 = this.v0, v1 = this.v1, v2 = this.v2;\n\n\treturn new Vector2(\n\t\tQuadraticBezier( t, v0.x, v1.x, v2.x ),\n\t\tQuadraticBezier( t, v0.y, v1.y, v2.y )\n\t);\n\n};\n\nvar PathPrototype = Object.assign( Object.create( CurvePath.prototype ), {\n\n\tfromPoints: function ( vectors ) {\n\n\t\tthis.moveTo( vectors[ 0 ].x, vectors[ 0 ].y );\n\n\t\tfor ( var i = 1, l = vectors.length; i < l; i ++ ) {\n\n\t\t\tthis.lineTo( vectors[ i ].x, vectors[ i ].y );\n\n\t\t}\n\n\t},\n\n\tmoveTo: function ( x, y ) {\n\n\t\tthis.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?\n\n\t},\n\n\tlineTo: function ( x, y ) {\n\n\t\tvar curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) );\n\t\tthis.curves.push( curve );\n\n\t\tthis.currentPoint.set( x, y );\n\n\t},\n\n\tquadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {\n\n\t\tvar curve = new QuadraticBezierCurve(\n\t\t\tthis.currentPoint.clone(),\n\t\t\tnew Vector2( aCPx, aCPy ),\n\t\t\tnew Vector2( aX, aY )\n\t\t);\n\n\t\tthis.curves.push( curve );\n\n\t\tthis.currentPoint.set( aX, aY );\n\n\t},\n\n\tbezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {\n\n\t\tvar curve = new CubicBezierCurve(\n\t\t\tthis.currentPoint.clone(),\n\t\t\tnew Vector2( aCP1x, aCP1y ),\n\t\t\tnew Vector2( aCP2x, aCP2y ),\n\t\t\tnew Vector2( aX, aY )\n\t\t);\n\n\t\tthis.curves.push( curve );\n\n\t\tthis.currentPoint.set( aX, aY );\n\n\t},\n\n\tsplineThru: function ( pts /*Array of Vector*/ ) {\n\n\t\tvar npts = [ this.currentPoint.clone() ].concat( pts );\n\n\t\tvar curve = new SplineCurve( npts );\n\t\tthis.curves.push( curve );\n\n\t\tthis.currentPoint.copy( pts[ pts.length - 1 ] );\n\n\t},\n\n\tarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {\n\n\t\tvar x0 = this.currentPoint.x;\n\t\tvar y0 = this.currentPoint.y;\n\n\t\tthis.absarc( aX + x0, aY + y0, aRadius,\n\t\t\taStartAngle, aEndAngle, aClockwise );\n\n\t},\n\n\tabsarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {\n\n\t\tthis.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );\n\n\t},\n\n\tellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {\n\n\t\tvar x0 = this.currentPoint.x;\n\t\tvar y0 = this.currentPoint.y;\n\n\t\tthis.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );\n\n\t},\n\n\tabsellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {\n\n\t\tvar curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );\n\n\t\tif ( this.curves.length > 0 ) {\n\n\t\t\t// if a previous curve is present, attempt to join\n\t\t\tvar firstPoint = curve.getPoint( 0 );\n\n\t\t\tif ( ! firstPoint.equals( this.currentPoint ) ) {\n\n\t\t\t\tthis.lineTo( firstPoint.x, firstPoint.y );\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.curves.push( curve );\n\n\t\tvar lastPoint = curve.getPoint( 1 );\n\t\tthis.currentPoint.copy( lastPoint );\n\n\t}\n\n} );\n\n/**\n * @author zz85 / http://www.lab4games.net/zz85/blog\n * Creates free form 2d path using series of points, lines or curves.\n **/\n\nfunction Path( points ) {\n\n\tCurvePath.call( this );\n\tthis.currentPoint = new Vector2();\n\n\tif ( points ) {\n\n\t\tthis.fromPoints( points );\n\n\t}\n\n}\n\nPath.prototype = PathPrototype;\nPathPrototype.constructor = Path;\n\n/**\n * @author zz85 / http://www.lab4games.net/zz85/blog\n * Defines a 2d shape plane using paths.\n **/\n\n// STEP 1 Create a path.\n// STEP 2 Turn path into shape.\n// STEP 3 ExtrudeGeometry takes in Shape/Shapes\n// STEP 3a - Extract points from each shape, turn to vertices\n// STEP 3b - Triangulate each shape, add faces.\n\nfunction Shape() {\n\n\tPath.apply( this, arguments );\n\n\tthis.holes = [];\n\n}\n\nShape.prototype = Object.assign( Object.create( PathPrototype ), {\n\n\tconstructor: Shape,\n\n\tgetPointsHoles: function ( divisions ) {\n\n\t\tvar holesPts = [];\n\n\t\tfor ( var i = 0, l = this.holes.length; i < l; i ++ ) {\n\n\t\t\tholesPts[ i ] = this.holes[ i ].getPoints( divisions );\n\n\t\t}\n\n\t\treturn holesPts;\n\n\t},\n\n\t// Get points of shape and holes (keypoints based on segments parameter)\n\n\textractAllPoints: function ( divisions ) {\n\n\t\treturn {\n\n\t\t\tshape: this.getPoints( divisions ),\n\t\t\tholes: this.getPointsHoles( divisions )\n\n\t\t};\n\n\t},\n\n\textractPoints: function ( divisions ) {\n\n\t\treturn this.extractAllPoints( divisions );\n\n\t}\n\n} );\n\n/**\n * @author zz85 / http://www.lab4games.net/zz85/blog\n * minimal class for proxing functions to Path. Replaces old \"extractSubpaths()\"\n **/\n\nfunction ShapePath() {\n\n\tthis.subPaths = [];\n\tthis.currentPath = null;\n\n}\n\nShapePath.prototype = {\n\n\tmoveTo: function ( x, y ) {\n\n\t\tthis.currentPath = new Path();\n\t\tthis.subPaths.push( this.currentPath );\n\t\tthis.currentPath.moveTo( x, y );\n\n\t},\n\n\tlineTo: function ( x, y ) {\n\n\t\tthis.currentPath.lineTo( x, y );\n\n\t},\n\n\tquadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {\n\n\t\tthis.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY );\n\n\t},\n\n\tbezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {\n\n\t\tthis.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY );\n\n\t},\n\n\tsplineThru: function ( pts ) {\n\n\t\tthis.currentPath.splineThru( pts );\n\n\t},\n\n\ttoShapes: function ( isCCW, noHoles ) {\n\n\t\tfunction toShapesNoHoles( inSubpaths ) {\n\n\t\t\tvar shapes = [];\n\n\t\t\tfor ( var i = 0, l = inSubpaths.length; i < l; i ++ ) {\n\n\t\t\t\tvar tmpPath = inSubpaths[ i ];\n\n\t\t\t\tvar tmpShape = new Shape();\n\t\t\t\ttmpShape.curves = tmpPath.curves;\n\n\t\t\t\tshapes.push( tmpShape );\n\n\t\t\t}\n\n\t\t\treturn shapes;\n\n\t\t}\n\n\t\tfunction isPointInsidePolygon( inPt, inPolygon ) {\n\n\t\t\tvar polyLen = inPolygon.length;\n\n\t\t\t// inPt on polygon contour => immediate success or\n\t\t\t// toggling of inside/outside at every single! intersection point of an edge\n\t\t\t// with the horizontal line through inPt, left of inPt\n\t\t\t// not counting lowerY endpoints of edges and whole edges on that line\n\t\t\tvar inside = false;\n\t\t\tfor ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {\n\n\t\t\t\tvar edgeLowPt = inPolygon[ p ];\n\t\t\t\tvar edgeHighPt = inPolygon[ q ];\n\n\t\t\t\tvar edgeDx = edgeHighPt.x - edgeLowPt.x;\n\t\t\t\tvar edgeDy = edgeHighPt.y - edgeLowPt.y;\n\n\t\t\t\tif ( Math.abs( edgeDy ) > Number.EPSILON ) {\n\n\t\t\t\t\t// not parallel\n\t\t\t\t\tif ( edgeDy < 0 ) {\n\n\t\t\t\t\t\tedgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx;\n\t\t\t\t\t\tedgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;\n\n\t\t\t\t\t}\n\t\t\t\t\tif ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) \t\tcontinue;\n\n\t\t\t\t\tif ( inPt.y === edgeLowPt.y ) {\n\n\t\t\t\t\t\tif ( inPt.x === edgeLowPt.x )\t\treturn\ttrue;\t\t// inPt is on contour ?\n\t\t\t\t\t\t// continue;\t\t\t\t// no intersection or edgeLowPt => doesn't count !!!\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tvar perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y );\n\t\t\t\t\t\tif ( perpEdge === 0 )\t\t\t\treturn\ttrue;\t\t// inPt is on contour ?\n\t\t\t\t\t\tif ( perpEdge < 0 ) \t\t\t\tcontinue;\n\t\t\t\t\t\tinside = ! inside;\t\t// true intersection left of inPt\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// parallel or collinear\n\t\t\t\t\tif ( inPt.y !== edgeLowPt.y ) \t\tcontinue;\t\t\t// parallel\n\t\t\t\t\t// edge lies on the same horizontal line as inPt\n\t\t\t\t\tif ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||\n\t\t\t\t\t\t ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) )\t\treturn\ttrue;\t// inPt: Point on contour !\n\t\t\t\t\t// continue;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn\tinside;\n\n\t\t}\n\n\t\tvar isClockWise = ShapeUtils.isClockWise;\n\n\t\tvar subPaths = this.subPaths;\n\t\tif ( subPaths.length === 0 ) return [];\n\n\t\tif ( noHoles === true )\treturn\ttoShapesNoHoles( subPaths );\n\n\n\t\tvar solid, tmpPath, tmpShape, shapes = [];\n\n\t\tif ( subPaths.length === 1 ) {\n\n\t\t\ttmpPath = subPaths[ 0 ];\n\t\t\ttmpShape = new Shape();\n\t\t\ttmpShape.curves = tmpPath.curves;\n\t\t\tshapes.push( tmpShape );\n\t\t\treturn shapes;\n\n\t\t}\n\n\t\tvar holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() );\n\t\tholesFirst = isCCW ? ! holesFirst : holesFirst;\n\n\t\t// console.log(\"Holes first\", holesFirst);\n\n\t\tvar betterShapeHoles = [];\n\t\tvar newShapes = [];\n\t\tvar newShapeHoles = [];\n\t\tvar mainIdx = 0;\n\t\tvar tmpPoints;\n\n\t\tnewShapes[ mainIdx ] = undefined;\n\t\tnewShapeHoles[ mainIdx ] = [];\n\n\t\tfor ( var i = 0, l = subPaths.length; i < l; i ++ ) {\n\n\t\t\ttmpPath = subPaths[ i ];\n\t\t\ttmpPoints = tmpPath.getPoints();\n\t\t\tsolid = isClockWise( tmpPoints );\n\t\t\tsolid = isCCW ? ! solid : solid;\n\n\t\t\tif ( solid ) {\n\n\t\t\t\tif ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) )\tmainIdx ++;\n\n\t\t\t\tnewShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints };\n\t\t\t\tnewShapes[ mainIdx ].s.curves = tmpPath.curves;\n\n\t\t\t\tif ( holesFirst )\tmainIdx ++;\n\t\t\t\tnewShapeHoles[ mainIdx ] = [];\n\n\t\t\t\t//console.log('cw', i);\n\n\t\t\t} else {\n\n\t\t\t\tnewShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } );\n\n\t\t\t\t//console.log('ccw', i);\n\n\t\t\t}\n\n\t\t}\n\n\t\t// only Holes? -> probably all Shapes with wrong orientation\n\t\tif ( ! newShapes[ 0 ] )\treturn\ttoShapesNoHoles( subPaths );\n\n\n\t\tif ( newShapes.length > 1 ) {\n\n\t\t\tvar ambiguous = false;\n\t\t\tvar toChange = [];\n\n\t\t\tfor ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {\n\n\t\t\t\tbetterShapeHoles[ sIdx ] = [];\n\n\t\t\t}\n\n\t\t\tfor ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {\n\n\t\t\t\tvar sho = newShapeHoles[ sIdx ];\n\n\t\t\t\tfor ( var hIdx = 0; hIdx < sho.length; hIdx ++ ) {\n\n\t\t\t\t\tvar ho = sho[ hIdx ];\n\t\t\t\t\tvar hole_unassigned = true;\n\n\t\t\t\t\tfor ( var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {\n\n\t\t\t\t\t\tif ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) {\n\n\t\t\t\t\t\t\tif ( sIdx !== s2Idx )\ttoChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } );\n\t\t\t\t\t\t\tif ( hole_unassigned ) {\n\n\t\t\t\t\t\t\t\thole_unassigned = false;\n\t\t\t\t\t\t\t\tbetterShapeHoles[ s2Idx ].push( ho );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tambiguous = true;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\t\t\t\t\tif ( hole_unassigned ) {\n\n\t\t\t\t\t\tbetterShapeHoles[ sIdx ].push( ho );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\t\t\t// console.log(\"ambiguous: \", ambiguous);\n\t\t\tif ( toChange.length > 0 ) {\n\n\t\t\t\t// console.log(\"to change: \", toChange);\n\t\t\t\tif ( ! ambiguous )\tnewShapeHoles = betterShapeHoles;\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar tmpHoles;\n\n\t\tfor ( var i = 0, il = newShapes.length; i < il; i ++ ) {\n\n\t\t\ttmpShape = newShapes[ i ].s;\n\t\t\tshapes.push( tmpShape );\n\t\t\ttmpHoles = newShapeHoles[ i ];\n\n\t\t\tfor ( var j = 0, jl = tmpHoles.length; j < jl; j ++ ) {\n\n\t\t\t\ttmpShape.holes.push( tmpHoles[ j ].h );\n\n\t\t\t}\n\n\t\t}\n\n\t\t//console.log(\"shape\", shapes);\n\n\t\treturn shapes;\n\n\t}\n\n};\n\n/**\n * @author zz85 / http://www.lab4games.net/zz85/blog\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction Font( data ) {\n\n\tthis.data = data;\n\n}\n\nObject.assign( Font.prototype, {\n\n\tisFont: true,\n\n\tgenerateShapes: function ( text, size, divisions ) {\n\n\t\tfunction createPaths( text ) {\n\n\t\t\tvar chars = String( text ).split( '' );\n\t\t\tvar scale = size / data.resolution;\n\t\t\tvar line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale;\n\n\t\t\tvar offsetX = 0, offsetY = 0;\n\n\t\t\tvar paths = [];\n\n\t\t\tfor ( var i = 0; i < chars.length; i ++ ) {\n\n\t\t\t\tvar char = chars[ i ];\n\n\t\t\t\tif ( char === '\\n' ) {\n\n\t\t\t\t\toffsetX = 0;\n\t\t\t\t\toffsetY -= line_height;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tvar ret = createPath( char, scale, offsetX, offsetY );\n\t\t\t\t\toffsetX += ret.offsetX;\n\t\t\t\t\tpaths.push( ret.path );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn paths;\n\n\t\t}\n\n\t\tfunction createPath( c, scale, offsetX, offsetY ) {\n\n\t\t\tvar glyph = data.glyphs[ c ] || data.glyphs[ '?' ];\n\n\t\t\tif ( ! glyph ) return;\n\n\t\t\tvar path = new ShapePath();\n\n\t\t\tvar pts = [];\n\t\t\tvar x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, laste;\n\n\t\t\tif ( glyph.o ) {\n\n\t\t\t\tvar outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );\n\n\t\t\t\tfor ( var i = 0, l = outline.length; i < l; ) {\n\n\t\t\t\t\tvar action = outline[ i ++ ];\n\n\t\t\t\t\tswitch ( action ) {\n\n\t\t\t\t\t\tcase 'm': // moveTo\n\n\t\t\t\t\t\t\tx = outline[ i ++ ] * scale + offsetX;\n\t\t\t\t\t\t\ty = outline[ i ++ ] * scale + offsetY;\n\n\t\t\t\t\t\t\tpath.moveTo( x, y );\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'l': // lineTo\n\n\t\t\t\t\t\t\tx = outline[ i ++ ] * scale + offsetX;\n\t\t\t\t\t\t\ty = outline[ i ++ ] * scale + offsetY;\n\n\t\t\t\t\t\t\tpath.lineTo( x, y );\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'q': // quadraticCurveTo\n\n\t\t\t\t\t\t\tcpx = outline[ i ++ ] * scale + offsetX;\n\t\t\t\t\t\t\tcpy = outline[ i ++ ] * scale + offsetY;\n\t\t\t\t\t\t\tcpx1 = outline[ i ++ ] * scale + offsetX;\n\t\t\t\t\t\t\tcpy1 = outline[ i ++ ] * scale + offsetY;\n\n\t\t\t\t\t\t\tpath.quadraticCurveTo( cpx1, cpy1, cpx, cpy );\n\n\t\t\t\t\t\t\tlaste = pts[ pts.length - 1 ];\n\n\t\t\t\t\t\t\tif ( laste ) {\n\n\t\t\t\t\t\t\t\tcpx0 = laste.x;\n\t\t\t\t\t\t\t\tcpy0 = laste.y;\n\n\t\t\t\t\t\t\t\tfor ( var i2 = 1; i2 <= divisions; i2 ++ ) {\n\n\t\t\t\t\t\t\t\t\tvar t = i2 / divisions;\n\t\t\t\t\t\t\t\t\tQuadraticBezier( t, cpx0, cpx1, cpx );\n\t\t\t\t\t\t\t\t\tQuadraticBezier( t, cpy0, cpy1, cpy );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'b': // bezierCurveTo\n\n\t\t\t\t\t\t\tcpx = outline[ i ++ ] * scale + offsetX;\n\t\t\t\t\t\t\tcpy = outline[ i ++ ] * scale + offsetY;\n\t\t\t\t\t\t\tcpx1 = outline[ i ++ ] * scale + offsetX;\n\t\t\t\t\t\t\tcpy1 = outline[ i ++ ] * scale + offsetY;\n\t\t\t\t\t\t\tcpx2 = outline[ i ++ ] * scale + offsetX;\n\t\t\t\t\t\t\tcpy2 = outline[ i ++ ] * scale + offsetY;\n\n\t\t\t\t\t\t\tpath.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy );\n\n\t\t\t\t\t\t\tlaste = pts[ pts.length - 1 ];\n\n\t\t\t\t\t\t\tif ( laste ) {\n\n\t\t\t\t\t\t\t\tcpx0 = laste.x;\n\t\t\t\t\t\t\t\tcpy0 = laste.y;\n\n\t\t\t\t\t\t\t\tfor ( var i2 = 1; i2 <= divisions; i2 ++ ) {\n\n\t\t\t\t\t\t\t\t\tvar t = i2 / divisions;\n\t\t\t\t\t\t\t\t\tCubicBezier( t, cpx0, cpx1, cpx2, cpx );\n\t\t\t\t\t\t\t\t\tCubicBezier( t, cpy0, cpy1, cpy2, cpy );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn { offsetX: glyph.ha * scale, path: path };\n\n\t\t}\n\n\t\t//\n\n\t\tif ( size === undefined ) size = 100;\n\t\tif ( divisions === undefined ) divisions = 4;\n\n\t\tvar data = this.data;\n\n\t\tvar paths = createPaths( text );\n\t\tvar shapes = [];\n\n\t\tfor ( var p = 0, pl = paths.length; p < pl; p ++ ) {\n\n\t\t\tArray.prototype.push.apply( shapes, paths[ p ].toShapes() );\n\n\t\t}\n\n\t\treturn shapes;\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction FontLoader( manager ) {\n\n\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n}\n\nObject.assign( FontLoader.prototype, {\n\n\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\tvar scope = this;\n\n\t\tvar loader = new FileLoader( this.manager );\n\t\tloader.load( url, function ( text ) {\n\n\t\t\tvar json;\n\n\t\t\ttry {\n\n\t\t\t\tjson = JSON.parse( text );\n\n\t\t\t} catch ( e ) {\n\n\t\t\t\tconsole.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' );\n\t\t\t\tjson = JSON.parse( text.substring( 65, text.length - 2 ) );\n\n\t\t\t}\n\n\t\t\tvar font = scope.parse( json );\n\n\t\t\tif ( onLoad ) onLoad( font );\n\n\t\t}, onProgress, onError );\n\n\t},\n\n\tparse: function ( json ) {\n\n\t\treturn new Font( json );\n\n\t}\n\n} );\n\nvar context;\n\nvar AudioContext = {\n\n\tgetContext: function () {\n\n\t\tif ( context === undefined ) {\n\n\t\t\tcontext = new ( window.AudioContext || window.webkitAudioContext )();\n\n\t\t}\n\n\t\treturn context;\n\n\t},\n\n\tsetContext: function ( value ) {\n\n\t\tcontext = value;\n\n\t}\n\n};\n\n/**\n * @author Reece Aaron Lecrivain / http://reecenotes.com/\n */\n\nfunction AudioLoader( manager ) {\n\n\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n}\n\nObject.assign( AudioLoader.prototype, {\n\n\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\tvar loader = new FileLoader( this.manager );\n\t\tloader.setResponseType( 'arraybuffer' );\n\t\tloader.load( url, function ( buffer ) {\n\n\t\t\tvar context = AudioContext.getContext();\n\n\t\t\tcontext.decodeAudioData( buffer, function ( audioBuffer ) {\n\n\t\t\t\tonLoad( audioBuffer );\n\n\t\t\t} );\n\n\t\t}, onProgress, onError );\n\n\t}\n\n} );\n\n/**\n * @author abelnation / http://github.com/abelnation\n */\n\nfunction RectAreaLight ( color, intensity, width, height ) {\n\n\tLight.call( this, color, intensity );\n\n\tthis.type = 'RectAreaLight';\n\n\tthis.position.set( 0, 1, 0 );\n\tthis.updateMatrix();\n\n\tthis.width = ( width !== undefined ) ? width : 10;\n\tthis.height = ( height !== undefined ) ? height : 10;\n\n\t// TODO (abelnation): distance/decay\n\n\t// TODO (abelnation): update method for RectAreaLight to update transform to lookat target\n\n\t// TODO (abelnation): shadows\n\t// this.shadow = new THREE.RectAreaLightShadow( new THREE.PerspectiveCamera( 90, 1, 0.5, 500 ) );\n\n}\n\n// TODO (abelnation): RectAreaLight update when light shape is changed\nRectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), {\n\n\tconstructor: RectAreaLight,\n\n\tisRectAreaLight: true,\n\n\tcopy: function ( source ) {\n\n\t\tLight.prototype.copy.call( this, source );\n\n\t\tthis.width = source.width;\n\t\tthis.height = source.height;\n\n\t\t// this.shadow = source.shadow.clone();\n\n\t\treturn this;\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction StereoCamera() {\n\n\tthis.type = 'StereoCamera';\n\n\tthis.aspect = 1;\n\n\tthis.eyeSep = 0.064;\n\n\tthis.cameraL = new PerspectiveCamera();\n\tthis.cameraL.layers.enable( 1 );\n\tthis.cameraL.matrixAutoUpdate = false;\n\n\tthis.cameraR = new PerspectiveCamera();\n\tthis.cameraR.layers.enable( 2 );\n\tthis.cameraR.matrixAutoUpdate = false;\n\n}\n\nObject.assign( StereoCamera.prototype, {\n\n\tupdate: ( function () {\n\n\t\tvar instance, focus, fov, aspect, near, far, zoom;\n\n\t\tvar eyeRight = new Matrix4();\n\t\tvar eyeLeft = new Matrix4();\n\n\t\treturn function update( camera ) {\n\n\t\t\tvar needsUpdate = instance !== this || focus !== camera.focus || fov !== camera.fov ||\n\t\t\t\t\t\t\t\t\t\t\t\taspect !== camera.aspect * this.aspect || near !== camera.near ||\n\t\t\t\t\t\t\t\t\t\t\t\tfar !== camera.far || zoom !== camera.zoom;\n\n\t\t\tif ( needsUpdate ) {\n\n\t\t\t\tinstance = this;\n\t\t\t\tfocus = camera.focus;\n\t\t\t\tfov = camera.fov;\n\t\t\t\taspect = camera.aspect * this.aspect;\n\t\t\t\tnear = camera.near;\n\t\t\t\tfar = camera.far;\n\t\t\t\tzoom = camera.zoom;\n\n\t\t\t\t// Off-axis stereoscopic effect based on\n\t\t\t\t// http://paulbourke.net/stereographics/stereorender/\n\n\t\t\t\tvar projectionMatrix = camera.projectionMatrix.clone();\n\t\t\t\tvar eyeSep = this.eyeSep / 2;\n\t\t\t\tvar eyeSepOnProjection = eyeSep * near / focus;\n\t\t\t\tvar ymax = ( near * Math.tan( _Math.DEG2RAD * fov * 0.5 ) ) / zoom;\n\t\t\t\tvar xmin, xmax;\n\n\t\t\t\t// translate xOffset\n\n\t\t\t\teyeLeft.elements[ 12 ] = - eyeSep;\n\t\t\t\teyeRight.elements[ 12 ] = eyeSep;\n\n\t\t\t\t// for left eye\n\n\t\t\t\txmin = - ymax * aspect + eyeSepOnProjection;\n\t\t\t\txmax = ymax * aspect + eyeSepOnProjection;\n\n\t\t\t\tprojectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin );\n\t\t\t\tprojectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );\n\n\t\t\t\tthis.cameraL.projectionMatrix.copy( projectionMatrix );\n\n\t\t\t\t// for right eye\n\n\t\t\t\txmin = - ymax * aspect - eyeSepOnProjection;\n\t\t\t\txmax = ymax * aspect - eyeSepOnProjection;\n\n\t\t\t\tprojectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin );\n\t\t\t\tprojectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );\n\n\t\t\t\tthis.cameraR.projectionMatrix.copy( projectionMatrix );\n\n\t\t\t}\n\n\t\t\tthis.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( eyeLeft );\n\t\t\tthis.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( eyeRight );\n\n\t\t};\n\n\t} )()\n\n} );\n\n/**\n * Camera for rendering cube maps\n *\t- renders scene into axis-aligned cube\n *\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction CubeCamera( near, far, cubeResolution ) {\n\n\tObject3D.call( this );\n\n\tthis.type = 'CubeCamera';\n\n\tvar fov = 90, aspect = 1;\n\n\tvar cameraPX = new PerspectiveCamera( fov, aspect, near, far );\n\tcameraPX.up.set( 0, - 1, 0 );\n\tcameraPX.lookAt( new Vector3( 1, 0, 0 ) );\n\tthis.add( cameraPX );\n\n\tvar cameraNX = new PerspectiveCamera( fov, aspect, near, far );\n\tcameraNX.up.set( 0, - 1, 0 );\n\tcameraNX.lookAt( new Vector3( - 1, 0, 0 ) );\n\tthis.add( cameraNX );\n\n\tvar cameraPY = new PerspectiveCamera( fov, aspect, near, far );\n\tcameraPY.up.set( 0, 0, 1 );\n\tcameraPY.lookAt( new Vector3( 0, 1, 0 ) );\n\tthis.add( cameraPY );\n\n\tvar cameraNY = new PerspectiveCamera( fov, aspect, near, far );\n\tcameraNY.up.set( 0, 0, - 1 );\n\tcameraNY.lookAt( new Vector3( 0, - 1, 0 ) );\n\tthis.add( cameraNY );\n\n\tvar cameraPZ = new PerspectiveCamera( fov, aspect, near, far );\n\tcameraPZ.up.set( 0, - 1, 0 );\n\tcameraPZ.lookAt( new Vector3( 0, 0, 1 ) );\n\tthis.add( cameraPZ );\n\n\tvar cameraNZ = new PerspectiveCamera( fov, aspect, near, far );\n\tcameraNZ.up.set( 0, - 1, 0 );\n\tcameraNZ.lookAt( new Vector3( 0, 0, - 1 ) );\n\tthis.add( cameraNZ );\n\n\tvar options = { format: RGBFormat, magFilter: LinearFilter, minFilter: LinearFilter };\n\n\tthis.renderTarget = new WebGLRenderTargetCube( cubeResolution, cubeResolution, options );\n\n\tthis.updateCubeMap = function ( renderer, scene ) {\n\n\t\tif ( this.parent === null ) this.updateMatrixWorld();\n\n\t\tvar renderTarget = this.renderTarget;\n\t\tvar generateMipmaps = renderTarget.texture.generateMipmaps;\n\n\t\trenderTarget.texture.generateMipmaps = false;\n\n\t\trenderTarget.activeCubeFace = 0;\n\t\trenderer.render( scene, cameraPX, renderTarget );\n\n\t\trenderTarget.activeCubeFace = 1;\n\t\trenderer.render( scene, cameraNX, renderTarget );\n\n\t\trenderTarget.activeCubeFace = 2;\n\t\trenderer.render( scene, cameraPY, renderTarget );\n\n\t\trenderTarget.activeCubeFace = 3;\n\t\trenderer.render( scene, cameraNY, renderTarget );\n\n\t\trenderTarget.activeCubeFace = 4;\n\t\trenderer.render( scene, cameraPZ, renderTarget );\n\n\t\trenderTarget.texture.generateMipmaps = generateMipmaps;\n\n\t\trenderTarget.activeCubeFace = 5;\n\t\trenderer.render( scene, cameraNZ, renderTarget );\n\n\t\trenderer.setRenderTarget( null );\n\n\t};\n\n}\n\nCubeCamera.prototype = Object.create( Object3D.prototype );\nCubeCamera.prototype.constructor = CubeCamera;\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction AudioListener() {\n\n\tObject3D.call( this );\n\n\tthis.type = 'AudioListener';\n\n\tthis.context = AudioContext.getContext();\n\n\tthis.gain = this.context.createGain();\n\tthis.gain.connect( this.context.destination );\n\n\tthis.filter = null;\n\n}\n\nAudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\tconstructor: AudioListener,\n\n\tgetInput: function () {\n\n\t\treturn this.gain;\n\n\t},\n\n\tremoveFilter: function ( ) {\n\n\t\tif ( this.filter !== null ) {\n\n\t\t\tthis.gain.disconnect( this.filter );\n\t\t\tthis.filter.disconnect( this.context.destination );\n\t\t\tthis.gain.connect( this.context.destination );\n\t\t\tthis.filter = null;\n\n\t\t}\n\n\t},\n\n\tgetFilter: function () {\n\n\t\treturn this.filter;\n\n\t},\n\n\tsetFilter: function ( value ) {\n\n\t\tif ( this.filter !== null ) {\n\n\t\t\tthis.gain.disconnect( this.filter );\n\t\t\tthis.filter.disconnect( this.context.destination );\n\n\t\t} else {\n\n\t\t\tthis.gain.disconnect( this.context.destination );\n\n\t\t}\n\n\t\tthis.filter = value;\n\t\tthis.gain.connect( this.filter );\n\t\tthis.filter.connect( this.context.destination );\n\n\t},\n\n\tgetMasterVolume: function () {\n\n\t\treturn this.gain.gain.value;\n\n\t},\n\n\tsetMasterVolume: function ( value ) {\n\n\t\tthis.gain.gain.value = value;\n\n\t},\n\n\tupdateMatrixWorld: ( function () {\n\n\t\tvar position = new Vector3();\n\t\tvar quaternion = new Quaternion();\n\t\tvar scale = new Vector3();\n\n\t\tvar orientation = new Vector3();\n\n\t\treturn function updateMatrixWorld( force ) {\n\n\t\t\tObject3D.prototype.updateMatrixWorld.call( this, force );\n\n\t\t\tvar listener = this.context.listener;\n\t\t\tvar up = this.up;\n\n\t\t\tthis.matrixWorld.decompose( position, quaternion, scale );\n\n\t\t\torientation.set( 0, 0, - 1 ).applyQuaternion( quaternion );\n\n\t\t\tif ( listener.positionX ) {\n\n\t\t\t\tlistener.positionX.setValueAtTime( position.x, this.context.currentTime );\n\t\t\t\tlistener.positionY.setValueAtTime( position.y, this.context.currentTime );\n\t\t\t\tlistener.positionZ.setValueAtTime( position.z, this.context.currentTime );\n\t\t\t\tlistener.forwardX.setValueAtTime( orientation.x, this.context.currentTime );\n\t\t\t\tlistener.forwardY.setValueAtTime( orientation.y, this.context.currentTime );\n\t\t\t\tlistener.forwardZ.setValueAtTime( orientation.z, this.context.currentTime );\n\t\t\t\tlistener.upX.setValueAtTime( up.x, this.context.currentTime );\n\t\t\t\tlistener.upY.setValueAtTime( up.y, this.context.currentTime );\n\t\t\t\tlistener.upZ.setValueAtTime( up.z, this.context.currentTime );\n\n\t\t\t} else {\n\n\t\t\t\tlistener.setPosition( position.x, position.y, position.z );\n\t\t\t\tlistener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z );\n\n\t\t\t}\n\n\t\t};\n\n\t} )()\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author Reece Aaron Lecrivain / http://reecenotes.com/\n */\n\nfunction Audio( listener ) {\n\n\tObject3D.call( this );\n\n\tthis.type = 'Audio';\n\n\tthis.context = listener.context;\n\n\tthis.gain = this.context.createGain();\n\tthis.gain.connect( listener.getInput() );\n\n\tthis.autoplay = false;\n\n\tthis.buffer = null;\n\tthis.loop = false;\n\tthis.startTime = 0;\n\tthis.playbackRate = 1;\n\tthis.isPlaying = false;\n\tthis.hasPlaybackControl = true;\n\tthis.sourceType = 'empty';\n\n\tthis.filters = [];\n\n}\n\nAudio.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\tconstructor: Audio,\n\n\tgetOutput: function () {\n\n\t\treturn this.gain;\n\n\t},\n\n\tsetNodeSource: function ( audioNode ) {\n\n\t\tthis.hasPlaybackControl = false;\n\t\tthis.sourceType = 'audioNode';\n\t\tthis.source = audioNode;\n\t\tthis.connect();\n\n\t\treturn this;\n\n\t},\n\n\tsetBuffer: function ( audioBuffer ) {\n\n\t\tthis.buffer = audioBuffer;\n\t\tthis.sourceType = 'buffer';\n\n\t\tif ( this.autoplay ) this.play();\n\n\t\treturn this;\n\n\t},\n\n\tplay: function () {\n\n\t\tif ( this.isPlaying === true ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: Audio is already playing.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tvar source = this.context.createBufferSource();\n\n\t\tsource.buffer = this.buffer;\n\t\tsource.loop = this.loop;\n\t\tsource.onended = this.onEnded.bind( this );\n\t\tsource.playbackRate.setValueAtTime( this.playbackRate, this.startTime );\n\t\tsource.start( 0, this.startTime );\n\n\t\tthis.isPlaying = true;\n\n\t\tthis.source = source;\n\n\t\treturn this.connect();\n\n\t},\n\n\tpause: function () {\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis.source.stop();\n\t\tthis.startTime = this.context.currentTime;\n\t\tthis.isPlaying = false;\n\n\t\treturn this;\n\n\t},\n\n\tstop: function () {\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis.source.stop();\n\t\tthis.startTime = 0;\n\t\tthis.isPlaying = false;\n\n\t\treturn this;\n\n\t},\n\n\tconnect: function () {\n\n\t\tif ( this.filters.length > 0 ) {\n\n\t\t\tthis.source.connect( this.filters[ 0 ] );\n\n\t\t\tfor ( var i = 1, l = this.filters.length; i < l; i ++ ) {\n\n\t\t\t\tthis.filters[ i - 1 ].connect( this.filters[ i ] );\n\n\t\t\t}\n\n\t\t\tthis.filters[ this.filters.length - 1 ].connect( this.getOutput() );\n\n\t\t} else {\n\n\t\t\tthis.source.connect( this.getOutput() );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tdisconnect: function () {\n\n\t\tif ( this.filters.length > 0 ) {\n\n\t\t\tthis.source.disconnect( this.filters[ 0 ] );\n\n\t\t\tfor ( var i = 1, l = this.filters.length; i < l; i ++ ) {\n\n\t\t\t\tthis.filters[ i - 1 ].disconnect( this.filters[ i ] );\n\n\t\t\t}\n\n\t\t\tthis.filters[ this.filters.length - 1 ].disconnect( this.getOutput() );\n\n\t\t} else {\n\n\t\t\tthis.source.disconnect( this.getOutput() );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tgetFilters: function () {\n\n\t\treturn this.filters;\n\n\t},\n\n\tsetFilters: function ( value ) {\n\n\t\tif ( ! value ) value = [];\n\n\t\tif ( this.isPlaying === true ) {\n\n\t\t\tthis.disconnect();\n\t\t\tthis.filters = value;\n\t\t\tthis.connect();\n\n\t\t} else {\n\n\t\t\tthis.filters = value;\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tgetFilter: function () {\n\n\t\treturn this.getFilters()[ 0 ];\n\n\t},\n\n\tsetFilter: function ( filter ) {\n\n\t\treturn this.setFilters( filter ? [ filter ] : [] );\n\n\t},\n\n\tsetPlaybackRate: function ( value ) {\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis.playbackRate = value;\n\n\t\tif ( this.isPlaying === true ) {\n\n\t\t\tthis.source.playbackRate.setValueAtTime( this.playbackRate, this.context.currentTime );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tgetPlaybackRate: function () {\n\n\t\treturn this.playbackRate;\n\n\t},\n\n\tonEnded: function () {\n\n\t\tthis.isPlaying = false;\n\n\t},\n\n\tgetLoop: function () {\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn false;\n\n\t\t}\n\n\t\treturn this.loop;\n\n\t},\n\n\tsetLoop: function ( value ) {\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis.loop = value;\n\n\t\tif ( this.isPlaying === true ) {\n\n\t\t\tthis.source.loop = this.loop;\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tgetVolume: function () {\n\n\t\treturn this.gain.gain.value;\n\n\t},\n\n\n\tsetVolume: function ( value ) {\n\n\t\tthis.gain.gain.value = value;\n\n\t\treturn this;\n\n\t}\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction PositionalAudio( listener ) {\n\n\tAudio.call( this, listener );\n\n\tthis.panner = this.context.createPanner();\n\tthis.panner.connect( this.gain );\n\n}\n\nPositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), {\n\n\tconstructor: PositionalAudio,\n\n\tgetOutput: function () {\n\n\t\treturn this.panner;\n\n\t},\n\n\tgetRefDistance: function () {\n\n\t\treturn this.panner.refDistance;\n\n\t},\n\n\tsetRefDistance: function ( value ) {\n\n\t\tthis.panner.refDistance = value;\n\n\t},\n\n\tgetRolloffFactor: function () {\n\n\t\treturn this.panner.rolloffFactor;\n\n\t},\n\n\tsetRolloffFactor: function ( value ) {\n\n\t\tthis.panner.rolloffFactor = value;\n\n\t},\n\n\tgetDistanceModel: function () {\n\n\t\treturn this.panner.distanceModel;\n\n\t},\n\n\tsetDistanceModel: function ( value ) {\n\n\t\tthis.panner.distanceModel = value;\n\n\t},\n\n\tgetMaxDistance: function () {\n\n\t\treturn this.panner.maxDistance;\n\n\t},\n\n\tsetMaxDistance: function ( value ) {\n\n\t\tthis.panner.maxDistance = value;\n\n\t},\n\n\tupdateMatrixWorld: ( function () {\n\n\t\tvar position = new Vector3();\n\n\t\treturn function updateMatrixWorld( force ) {\n\n\t\t\tObject3D.prototype.updateMatrixWorld.call( this, force );\n\n\t\t\tposition.setFromMatrixPosition( this.matrixWorld );\n\n\t\t\tthis.panner.setPosition( position.x, position.y, position.z );\n\n\t\t};\n\n\t} )()\n\n\n} );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction AudioAnalyser( audio, fftSize ) {\n\n\tthis.analyser = audio.context.createAnalyser();\n\tthis.analyser.fftSize = fftSize !== undefined ? fftSize : 2048;\n\n\tthis.data = new Uint8Array( this.analyser.frequencyBinCount );\n\n\taudio.getOutput().connect( this.analyser );\n\n}\n\nObject.assign( AudioAnalyser.prototype, {\n\n\tgetFrequencyData: function () {\n\n\t\tthis.analyser.getByteFrequencyData( this.data );\n\n\t\treturn this.data;\n\n\t},\n\n\tgetAverageFrequency: function () {\n\n\t\tvar value = 0, data = this.getFrequencyData();\n\n\t\tfor ( var i = 0; i < data.length; i ++ ) {\n\n\t\t\tvalue += data[ i ];\n\n\t\t}\n\n\t\treturn value / data.length;\n\n\t}\n\n} );\n\n/**\n *\n * Buffered scene graph property that allows weighted accumulation.\n *\n *\n * @author Ben Houston / http://clara.io/\n * @author David Sarno / http://lighthaus.us/\n * @author tschw\n */\n\nfunction PropertyMixer( binding, typeName, valueSize ) {\n\n\tthis.binding = binding;\n\tthis.valueSize = valueSize;\n\n\tvar bufferType = Float64Array,\n\t\tmixFunction;\n\n\tswitch ( typeName ) {\n\n\t\tcase 'quaternion':\n\t\t\tmixFunction = this._slerp;\n\t\t\tbreak;\n\n\t\tcase 'string':\n\t\tcase 'bool':\n\t\t\tbufferType = Array;\n\t\t\tmixFunction = this._select;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tmixFunction = this._lerp;\n\n\t}\n\n\tthis.buffer = new bufferType( valueSize * 4 );\n\t// layout: [ incoming | accu0 | accu1 | orig ]\n\t//\n\t// interpolators can use .buffer as their .result\n\t// the data then goes to 'incoming'\n\t//\n\t// 'accu0' and 'accu1' are used frame-interleaved for\n\t// the cumulative result and are compared to detect\n\t// changes\n\t//\n\t// 'orig' stores the original state of the property\n\n\tthis._mixBufferRegion = mixFunction;\n\n\tthis.cumulativeWeight = 0;\n\n\tthis.useCount = 0;\n\tthis.referenceCount = 0;\n\n}\n\nPropertyMixer.prototype = {\n\n\tconstructor: PropertyMixer,\n\n\t// accumulate data in the 'incoming' region into 'accu'\n\taccumulate: function( accuIndex, weight ) {\n\n\t\t// note: happily accumulating nothing when weight = 0, the caller knows\n\t\t// the weight and shouldn't have made the call in the first place\n\n\t\tvar buffer = this.buffer,\n\t\t\tstride = this.valueSize,\n\t\t\toffset = accuIndex * stride + stride,\n\n\t\t\tcurrentWeight = this.cumulativeWeight;\n\n\t\tif ( currentWeight === 0 ) {\n\n\t\t\t// accuN := incoming * weight\n\n\t\t\tfor ( var i = 0; i !== stride; ++ i ) {\n\n\t\t\t\tbuffer[ offset + i ] = buffer[ i ];\n\n\t\t\t}\n\n\t\t\tcurrentWeight = weight;\n\n\t\t} else {\n\n\t\t\t// accuN := accuN + incoming * weight\n\n\t\t\tcurrentWeight += weight;\n\t\t\tvar mix = weight / currentWeight;\n\t\t\tthis._mixBufferRegion( buffer, offset, 0, mix, stride );\n\n\t\t}\n\n\t\tthis.cumulativeWeight = currentWeight;\n\n\t},\n\n\t// apply the state of 'accu' to the binding when accus differ\n\tapply: function( accuIndex ) {\n\n\t\tvar stride = this.valueSize,\n\t\t\tbuffer = this.buffer,\n\t\t\toffset = accuIndex * stride + stride,\n\n\t\t\tweight = this.cumulativeWeight,\n\n\t\t\tbinding = this.binding;\n\n\t\tthis.cumulativeWeight = 0;\n\n\t\tif ( weight < 1 ) {\n\n\t\t\t// accuN := accuN + original * ( 1 - cumulativeWeight )\n\n\t\t\tvar originalValueOffset = stride * 3;\n\n\t\t\tthis._mixBufferRegion(\n\t\t\t\t\tbuffer, offset, originalValueOffset, 1 - weight, stride );\n\n\t\t}\n\n\t\tfor ( var i = stride, e = stride + stride; i !== e; ++ i ) {\n\n\t\t\tif ( buffer[ i ] !== buffer[ i + stride ] ) {\n\n\t\t\t\t// value has changed -> update scene graph\n\n\t\t\t\tbinding.setValue( buffer, offset );\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t},\n\n\t// remember the state of the bound property and copy it to both accus\n\tsaveOriginalState: function() {\n\n\t\tvar binding = this.binding;\n\n\t\tvar buffer = this.buffer,\n\t\t\tstride = this.valueSize,\n\n\t\t\toriginalValueOffset = stride * 3;\n\n\t\tbinding.getValue( buffer, originalValueOffset );\n\n\t\t// accu[0..1] := orig -- initially detect changes against the original\n\t\tfor ( var i = stride, e = originalValueOffset; i !== e; ++ i ) {\n\n\t\t\tbuffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ];\n\n\t\t}\n\n\t\tthis.cumulativeWeight = 0;\n\n\t},\n\n\t// apply the state previously taken via 'saveOriginalState' to the binding\n\trestoreOriginalState: function() {\n\n\t\tvar originalValueOffset = this.valueSize * 3;\n\t\tthis.binding.setValue( this.buffer, originalValueOffset );\n\n\t},\n\n\n\t// mix functions\n\n\t_select: function( buffer, dstOffset, srcOffset, t, stride ) {\n\n\t\tif ( t >= 0.5 ) {\n\n\t\t\tfor ( var i = 0; i !== stride; ++ i ) {\n\n\t\t\t\tbuffer[ dstOffset + i ] = buffer[ srcOffset + i ];\n\n\t\t\t}\n\n\t\t}\n\n\t},\n\n\t_slerp: function( buffer, dstOffset, srcOffset, t, stride ) {\n\n\t\tQuaternion.slerpFlat( buffer, dstOffset,\n\t\t\t\tbuffer, dstOffset, buffer, srcOffset, t );\n\n\t},\n\n\t_lerp: function( buffer, dstOffset, srcOffset, t, stride ) {\n\n\t\tvar s = 1 - t;\n\n\t\tfor ( var i = 0; i !== stride; ++ i ) {\n\n\t\t\tvar j = dstOffset + i;\n\n\t\t\tbuffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t;\n\n\t\t}\n\n\t}\n\n};\n\n/**\n *\n * A reference to a real property in the scene graph.\n *\n *\n * @author Ben Houston / http://clara.io/\n * @author David Sarno / http://lighthaus.us/\n * @author tschw\n */\n\nfunction PropertyBinding( rootNode, path, parsedPath ) {\n\n\tthis.path = path;\n\tthis.parsedPath = parsedPath ||\n\t\t\tPropertyBinding.parseTrackName( path );\n\n\tthis.node = PropertyBinding.findNode(\n\t\t\trootNode, this.parsedPath.nodeName ) || rootNode;\n\n\tthis.rootNode = rootNode;\n\n}\n\nPropertyBinding.prototype = {\n\n\tconstructor: PropertyBinding,\n\n\tgetValue: function getValue_unbound( targetArray, offset ) {\n\n\t\tthis.bind();\n\t\tthis.getValue( targetArray, offset );\n\n\t\t// Note: This class uses a State pattern on a per-method basis:\n\t\t// 'bind' sets 'this.getValue' / 'setValue' and shadows the\n\t\t// prototype version of these methods with one that represents\n\t\t// the bound state. When the property is not found, the methods\n\t\t// become no-ops.\n\n\t},\n\n\tsetValue: function getValue_unbound( sourceArray, offset ) {\n\n\t\tthis.bind();\n\t\tthis.setValue( sourceArray, offset );\n\n\t},\n\n\t// create getter / setter pair for a property in the scene graph\n\tbind: function() {\n\n\t\tvar targetObject = this.node,\n\t\t\tparsedPath = this.parsedPath,\n\n\t\t\tobjectName = parsedPath.objectName,\n\t\t\tpropertyName = parsedPath.propertyName,\n\t\t\tpropertyIndex = parsedPath.propertyIndex;\n\n\t\tif ( ! targetObject ) {\n\n\t\t\ttargetObject = PropertyBinding.findNode(\n\t\t\t\t\tthis.rootNode, parsedPath.nodeName ) || this.rootNode;\n\n\t\t\tthis.node = targetObject;\n\n\t\t}\n\n\t\t// set fail state so we can just 'return' on error\n\t\tthis.getValue = this._getValue_unavailable;\n\t\tthis.setValue = this._setValue_unavailable;\n\n \t\t// ensure there is a value node\n\t\tif ( ! targetObject ) {\n\n\t\t\tconsole.error( \" trying to update node for track: \" + this.path + \" but it wasn't found.\" );\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( objectName ) {\n\n\t\t\tvar objectIndex = parsedPath.objectIndex;\n\n\t\t\t// special cases were we need to reach deeper into the hierarchy to get the face materials....\n\t\t\tswitch ( objectName ) {\n\n\t\t\t\tcase 'materials':\n\n\t\t\t\t\tif ( ! targetObject.material ) {\n\n\t\t\t\t\t\tconsole.error( ' can not bind to material as node does not have a material', this );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ! targetObject.material.materials ) {\n\n\t\t\t\t\t\tconsole.error( ' can not bind to material.materials as node.material does not have a materials array', this );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttargetObject = targetObject.material.materials;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'bones':\n\n\t\t\t\t\tif ( ! targetObject.skeleton ) {\n\n\t\t\t\t\t\tconsole.error( ' can not bind to bones as node does not have a skeleton', this );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// potential future optimization: skip this if propertyIndex is already an integer\n\t\t\t\t\t// and convert the integer string to a true integer.\n\n\t\t\t\t\ttargetObject = targetObject.skeleton.bones;\n\n\t\t\t\t\t// support resolving morphTarget names into indices.\n\t\t\t\t\tfor ( var i = 0; i < targetObject.length; i ++ ) {\n\n\t\t\t\t\t\tif ( targetObject[ i ].name === objectIndex ) {\n\n\t\t\t\t\t\t\tobjectIndex = i;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tif ( targetObject[ objectName ] === undefined ) {\n\n\t\t\t\t\t\tconsole.error( ' can not bind to objectName of node, undefined', this );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttargetObject = targetObject[ objectName ];\n\n\t\t\t}\n\n\n\t\t\tif ( objectIndex !== undefined ) {\n\n\t\t\t\tif ( targetObject[ objectIndex ] === undefined ) {\n\n\t\t\t\t\tconsole.error( \" trying to bind to objectIndex of objectName, but is undefined:\", this, targetObject );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\ttargetObject = targetObject[ objectIndex ];\n\n\t\t\t}\n\n\t\t}\n\n\t\t// resolve property\n\t\tvar nodeProperty = targetObject[ propertyName ];\n\n\t\tif ( nodeProperty === undefined ) {\n\n\t\t\tvar nodeName = parsedPath.nodeName;\n\n\t\t\tconsole.error( \" trying to update property for track: \" + nodeName +\n\t\t\t\t\t'.' + propertyName + \" but it wasn't found.\", targetObject );\n\t\t\treturn;\n\n\t\t}\n\n\t\t// determine versioning scheme\n\t\tvar versioning = this.Versioning.None;\n\n\t\tif ( targetObject.needsUpdate !== undefined ) { // material\n\n\t\t\tversioning = this.Versioning.NeedsUpdate;\n\t\t\tthis.targetObject = targetObject;\n\n\t\t} else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform\n\n\t\t\tversioning = this.Versioning.MatrixWorldNeedsUpdate;\n\t\t\tthis.targetObject = targetObject;\n\n\t\t}\n\n\t\t// determine how the property gets bound\n\t\tvar bindingType = this.BindingType.Direct;\n\n\t\tif ( propertyIndex !== undefined ) {\n\t\t\t// access a sub element of the property array (only primitives are supported right now)\n\n\t\t\tif ( propertyName === \"morphTargetInfluences\" ) {\n\t\t\t\t// potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.\n\n\t\t\t\t// support resolving morphTarget names into indices.\n\t\t\t\tif ( ! targetObject.geometry ) {\n\n\t\t\t\t\tconsole.error( ' can not bind to morphTargetInfluences becasuse node does not have a geometry', this );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\tif ( ! targetObject.geometry.morphTargets ) {\n\n\t\t\t\t\tconsole.error( ' can not bind to morphTargetInfluences becasuse node does not have a geometry.morphTargets', this );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\tfor ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) {\n\n\t\t\t\t\tif ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) {\n\n\t\t\t\t\t\tpropertyIndex = i;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tbindingType = this.BindingType.ArrayElement;\n\n\t\t\tthis.resolvedProperty = nodeProperty;\n\t\t\tthis.propertyIndex = propertyIndex;\n\n\t\t} else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {\n\t\t\t// must use copy for Object3D.Euler/Quaternion\n\n\t\t\tbindingType = this.BindingType.HasFromToArray;\n\n\t\t\tthis.resolvedProperty = nodeProperty;\n\n\t\t} else if ( nodeProperty.length !== undefined ) {\n\n\t\t\tbindingType = this.BindingType.EntireArray;\n\n\t\t\tthis.resolvedProperty = nodeProperty;\n\n\t\t} else {\n\n\t\t\tthis.propertyName = propertyName;\n\n\t\t}\n\n\t\t// select getter / setter\n\t\tthis.getValue = this.GetterByBindingType[ bindingType ];\n\t\tthis.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];\n\n\t},\n\n\tunbind: function() {\n\n\t\tthis.node = null;\n\n\t\t// back to the prototype version of getValue / setValue\n\t\t// note: avoiding to mutate the shape of 'this' via 'delete'\n\t\tthis.getValue = this._getValue_unbound;\n\t\tthis.setValue = this._setValue_unbound;\n\n\t}\n\n};\n\nObject.assign( PropertyBinding.prototype, { // prototype, continued\n\n\t// these are used to \"bind\" a nonexistent property\n\t_getValue_unavailable: function() {},\n\t_setValue_unavailable: function() {},\n\n\t// initial state of these methods that calls 'bind'\n\t_getValue_unbound: PropertyBinding.prototype.getValue,\n\t_setValue_unbound: PropertyBinding.prototype.setValue,\n\n\tBindingType: {\n\t\tDirect: 0,\n\t\tEntireArray: 1,\n\t\tArrayElement: 2,\n\t\tHasFromToArray: 3\n\t},\n\n\tVersioning: {\n\t\tNone: 0,\n\t\tNeedsUpdate: 1,\n\t\tMatrixWorldNeedsUpdate: 2\n\t},\n\n\tGetterByBindingType: [\n\n\t\tfunction getValue_direct( buffer, offset ) {\n\n\t\t\tbuffer[ offset ] = this.node[ this.propertyName ];\n\n\t\t},\n\n\t\tfunction getValue_array( buffer, offset ) {\n\n\t\t\tvar source = this.resolvedProperty;\n\n\t\t\tfor ( var i = 0, n = source.length; i !== n; ++ i ) {\n\n\t\t\t\tbuffer[ offset ++ ] = source[ i ];\n\n\t\t\t}\n\n\t\t},\n\n\t\tfunction getValue_arrayElement( buffer, offset ) {\n\n\t\t\tbuffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];\n\n\t\t},\n\n\t\tfunction getValue_toArray( buffer, offset ) {\n\n\t\t\tthis.resolvedProperty.toArray( buffer, offset );\n\n\t\t}\n\n\t],\n\n\tSetterByBindingTypeAndVersioning: [\n\n\t\t[\n\t\t\t// Direct\n\n\t\t\tfunction setValue_direct( buffer, offset ) {\n\n\t\t\t\tthis.node[ this.propertyName ] = buffer[ offset ];\n\n\t\t\t},\n\n\t\t\tfunction setValue_direct_setNeedsUpdate( buffer, offset ) {\n\n\t\t\t\tthis.node[ this.propertyName ] = buffer[ offset ];\n\t\t\t\tthis.targetObject.needsUpdate = true;\n\n\t\t\t},\n\n\t\t\tfunction setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {\n\n\t\t\t\tthis.node[ this.propertyName ] = buffer[ offset ];\n\t\t\t\tthis.targetObject.matrixWorldNeedsUpdate = true;\n\n\t\t\t}\n\n\t\t], [\n\n\t\t\t// EntireArray\n\n\t\t\tfunction setValue_array( buffer, offset ) {\n\n\t\t\t\tvar dest = this.resolvedProperty;\n\n\t\t\t\tfor ( var i = 0, n = dest.length; i !== n; ++ i ) {\n\n\t\t\t\t\tdest[ i ] = buffer[ offset ++ ];\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tfunction setValue_array_setNeedsUpdate( buffer, offset ) {\n\n\t\t\t\tvar dest = this.resolvedProperty;\n\n\t\t\t\tfor ( var i = 0, n = dest.length; i !== n; ++ i ) {\n\n\t\t\t\t\tdest[ i ] = buffer[ offset ++ ];\n\n\t\t\t\t}\n\n\t\t\t\tthis.targetObject.needsUpdate = true;\n\n\t\t\t},\n\n\t\t\tfunction setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) {\n\n\t\t\t\tvar dest = this.resolvedProperty;\n\n\t\t\t\tfor ( var i = 0, n = dest.length; i !== n; ++ i ) {\n\n\t\t\t\t\tdest[ i ] = buffer[ offset ++ ];\n\n\t\t\t\t}\n\n\t\t\t\tthis.targetObject.matrixWorldNeedsUpdate = true;\n\n\t\t\t}\n\n\t\t], [\n\n\t\t\t// ArrayElement\n\n\t\t\tfunction setValue_arrayElement( buffer, offset ) {\n\n\t\t\t\tthis.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];\n\n\t\t\t},\n\n\t\t\tfunction setValue_arrayElement_setNeedsUpdate( buffer, offset ) {\n\n\t\t\t\tthis.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];\n\t\t\t\tthis.targetObject.needsUpdate = true;\n\n\t\t\t},\n\n\t\t\tfunction setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {\n\n\t\t\t\tthis.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];\n\t\t\t\tthis.targetObject.matrixWorldNeedsUpdate = true;\n\n\t\t\t}\n\n\t\t], [\n\n\t\t\t// HasToFromArray\n\n\t\t\tfunction setValue_fromArray( buffer, offset ) {\n\n\t\t\t\tthis.resolvedProperty.fromArray( buffer, offset );\n\n\t\t\t},\n\n\t\t\tfunction setValue_fromArray_setNeedsUpdate( buffer, offset ) {\n\n\t\t\t\tthis.resolvedProperty.fromArray( buffer, offset );\n\t\t\t\tthis.targetObject.needsUpdate = true;\n\n\t\t\t},\n\n\t\t\tfunction setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {\n\n\t\t\t\tthis.resolvedProperty.fromArray( buffer, offset );\n\t\t\t\tthis.targetObject.matrixWorldNeedsUpdate = true;\n\n\t\t\t}\n\n\t\t]\n\n\t]\n\n} );\n\nPropertyBinding.Composite =\n\t\tfunction( targetGroup, path, optionalParsedPath ) {\n\n\tvar parsedPath = optionalParsedPath ||\n\t\t\tPropertyBinding.parseTrackName( path );\n\n\tthis._targetGroup = targetGroup;\n\tthis._bindings = targetGroup.subscribe_( path, parsedPath );\n\n};\n\nPropertyBinding.Composite.prototype = {\n\n\tconstructor: PropertyBinding.Composite,\n\n\tgetValue: function( array, offset ) {\n\n\t\tthis.bind(); // bind all binding\n\n\t\tvar firstValidIndex = this._targetGroup.nCachedObjects_,\n\t\t\tbinding = this._bindings[ firstValidIndex ];\n\n\t\t// and only call .getValue on the first\n\t\tif ( binding !== undefined ) binding.getValue( array, offset );\n\n\t},\n\n\tsetValue: function( array, offset ) {\n\n\t\tvar bindings = this._bindings;\n\n\t\tfor ( var i = this._targetGroup.nCachedObjects_,\n\t\t\t\tn = bindings.length; i !== n; ++ i ) {\n\n\t\t\tbindings[ i ].setValue( array, offset );\n\n\t\t}\n\n\t},\n\n\tbind: function() {\n\n\t\tvar bindings = this._bindings;\n\n\t\tfor ( var i = this._targetGroup.nCachedObjects_,\n\t\t\t\tn = bindings.length; i !== n; ++ i ) {\n\n\t\t\tbindings[ i ].bind();\n\n\t\t}\n\n\t},\n\n\tunbind: function() {\n\n\t\tvar bindings = this._bindings;\n\n\t\tfor ( var i = this._targetGroup.nCachedObjects_,\n\t\t\t\tn = bindings.length; i !== n; ++ i ) {\n\n\t\t\tbindings[ i ].unbind();\n\n\t\t}\n\n\t}\n\n};\n\nPropertyBinding.create = function( root, path, parsedPath ) {\n\n\tif ( ! ( root && root.isAnimationObjectGroup ) ) {\n\n\t\treturn new PropertyBinding( root, path, parsedPath );\n\n\t} else {\n\n\t\treturn new PropertyBinding.Composite( root, path, parsedPath );\n\n\t}\n\n};\n\nPropertyBinding.parseTrackName = function( trackName ) {\n\n\t// matches strings in the form of:\n\t// nodeName.property\n\t// nodeName.property[accessor]\n\t// nodeName.material.property[accessor]\n\t// uuid.property[accessor]\n\t// uuid.objectName[objectIndex].propertyName[propertyIndex]\n\t// parentName/nodeName.property\n\t// parentName/parentName/nodeName.property[index]\n\t// .bone[Armature.DEF_cog].position\n\t// scene:helium_balloon_model:helium_balloon_model.position\n\t// created and tested via https://regex101.com/#javascript\n\n\tvar re = /^((?:[\\w-]+[\\/:])*)([\\w-]+)?(?:\\.([\\w-]+)(?:\\[(.+)\\])?)?\\.([\\w-]+)(?:\\[(.+)\\])?$/;\n\tvar matches = re.exec( trackName );\n\n\tif ( ! matches ) {\n\n\t\tthrow new Error( \"cannot parse trackName at all: \" + trackName );\n\n\t}\n\n\tvar results = {\n\t\t// directoryName: matches[ 1 ], // (tschw) currently unused\n\t\tnodeName: matches[ 2 ], \t// allowed to be null, specified root node.\n\t\tobjectName: matches[ 3 ],\n\t\tobjectIndex: matches[ 4 ],\n\t\tpropertyName: matches[ 5 ],\n\t\tpropertyIndex: matches[ 6 ]\t// allowed to be null, specifies that the whole property is set.\n\t};\n\n\tif ( results.propertyName === null || results.propertyName.length === 0 ) {\n\n\t\tthrow new Error( \"can not parse propertyName from trackName: \" + trackName );\n\n\t}\n\n\treturn results;\n\n};\n\nPropertyBinding.findNode = function( root, nodeName ) {\n\n\tif ( ! nodeName || nodeName === \"\" || nodeName === \"root\" || nodeName === \".\" || nodeName === -1 || nodeName === root.name || nodeName === root.uuid ) {\n\n\t\treturn root;\n\n\t}\n\n\t// search into skeleton bones.\n\tif ( root.skeleton ) {\n\n\t\tvar searchSkeleton = function( skeleton ) {\n\n\t\t\tfor( var i = 0; i < skeleton.bones.length; i ++ ) {\n\n\t\t\t\tvar bone = skeleton.bones[ i ];\n\n\t\t\t\tif ( bone.name === nodeName ) {\n\n\t\t\t\t\treturn bone;\n\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\n\t\t};\n\n\t\tvar bone = searchSkeleton( root.skeleton );\n\n\t\tif ( bone ) {\n\n\t\t\treturn bone;\n\n\t\t}\n\t}\n\n\t// search into node subtree.\n\tif ( root.children ) {\n\n\t\tvar searchNodeSubtree = function( children ) {\n\n\t\t\tfor( var i = 0; i < children.length; i ++ ) {\n\n\t\t\t\tvar childNode = children[ i ];\n\n\t\t\t\tif ( childNode.name === nodeName || childNode.uuid === nodeName ) {\n\n\t\t\t\t\treturn childNode;\n\n\t\t\t\t}\n\n\t\t\t\tvar result = searchNodeSubtree( childNode.children );\n\n\t\t\t\tif ( result ) return result;\n\n\t\t\t}\n\n\t\t\treturn null;\n\n\t\t};\n\n\t\tvar subTreeNode = searchNodeSubtree( root.children );\n\n\t\tif ( subTreeNode ) {\n\n\t\t\treturn subTreeNode;\n\n\t\t}\n\n\t}\n\n\treturn null;\n\n};\n\n/**\n *\n * A group of objects that receives a shared animation state.\n *\n * Usage:\n *\n * \t-\tAdd objects you would otherwise pass as 'root' to the\n * \t\tconstructor or the .clipAction method of AnimationMixer.\n *\n * \t-\tInstead pass this object as 'root'.\n *\n * \t-\tYou can also add and remove objects later when the mixer\n * \t\tis running.\n *\n * Note:\n *\n * \tObjects of this class appear as one object to the mixer,\n * \tso cache control of the individual objects must be done\n * \ton the group.\n *\n * Limitation:\n *\n * \t- \tThe animated properties must be compatible among the\n * \t\tall objects in the group.\n *\n * -\tA single property can either be controlled through a\n * \ttarget group or directly, but not both.\n *\n * @author tschw\n */\n\nfunction AnimationObjectGroup( var_args ) {\n\n\tthis.uuid = _Math.generateUUID();\n\n\t// cached objects followed by the active ones\n\tthis._objects = Array.prototype.slice.call( arguments );\n\n\tthis.nCachedObjects_ = 0;\t\t\t// threshold\n\t// note: read by PropertyBinding.Composite\n\n\tvar indices = {};\n\tthis._indicesByUUID = indices;\t\t// for bookkeeping\n\n\tfor ( var i = 0, n = arguments.length; i !== n; ++ i ) {\n\n\t\tindices[ arguments[ i ].uuid ] = i;\n\n\t}\n\n\tthis._paths = [];\t\t\t\t\t// inside: string\n\tthis._parsedPaths = [];\t\t\t\t// inside: { we don't care, here }\n\tthis._bindings = []; \t\t\t\t// inside: Array< PropertyBinding >\n\tthis._bindingsIndicesByPath = {}; \t// inside: indices in these arrays\n\n\tvar scope = this;\n\n\tthis.stats = {\n\n\t\tobjects: {\n\t\t\tget total() { return scope._objects.length; },\n\t\t\tget inUse() { return this.total - scope.nCachedObjects_; }\n\t\t},\n\n\t\tget bindingsPerObject() { return scope._bindings.length; }\n\n\t};\n\n}\n\nAnimationObjectGroup.prototype = {\n\n\tconstructor: AnimationObjectGroup,\n\n\tisAnimationObjectGroup: true,\n\n\tadd: function( var_args ) {\n\n\t\tvar objects = this._objects,\n\t\t\tnObjects = objects.length,\n\t\t\tnCachedObjects = this.nCachedObjects_,\n\t\t\tindicesByUUID = this._indicesByUUID,\n\t\t\tpaths = this._paths,\n\t\t\tparsedPaths = this._parsedPaths,\n\t\t\tbindings = this._bindings,\n\t\t\tnBindings = bindings.length;\n\n\t\tfor ( var i = 0, n = arguments.length; i !== n; ++ i ) {\n\n\t\t\tvar object = arguments[ i ],\n\t\t\t\tuuid = object.uuid,\n\t\t\t\tindex = indicesByUUID[ uuid ],\n\t\t\t\tknownObject = undefined;\n\n\t\t\tif ( index === undefined ) {\n\n\t\t\t\t// unknown object -> add it to the ACTIVE region\n\n\t\t\t\tindex = nObjects ++;\n\t\t\t\tindicesByUUID[ uuid ] = index;\n\t\t\t\tobjects.push( object );\n\n\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\tfor ( var j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\tbindings[ j ].push(\n\t\t\t\t\t\t\tnew PropertyBinding(\n\t\t\t\t\t\t\t\tobject, paths[ j ], parsedPaths[ j ] ) );\n\n\t\t\t\t}\n\n\t\t\t} else if ( index < nCachedObjects ) {\n\n\t\t\t\tknownObject = objects[ index ];\n\n\t\t\t\t// move existing object to the ACTIVE region\n\n\t\t\t\tvar firstActiveIndex = -- nCachedObjects,\n\t\t\t\t\tlastCachedObject = objects[ firstActiveIndex ];\n\n\t\t\t\tindicesByUUID[ lastCachedObject.uuid ] = index;\n\t\t\t\tobjects[ index ] = lastCachedObject;\n\n\t\t\t\tindicesByUUID[ uuid ] = firstActiveIndex;\n\t\t\t\tobjects[ firstActiveIndex ] = object;\n\n\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\tfor ( var j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\tvar bindingsForPath = bindings[ j ],\n\t\t\t\t\t\tlastCached = bindingsForPath[ firstActiveIndex ],\n\t\t\t\t\t\tbinding = bindingsForPath[ index ];\n\n\t\t\t\t\tbindingsForPath[ index ] = lastCached;\n\n\t\t\t\t\tif ( binding === undefined ) {\n\n\t\t\t\t\t\t// since we do not bother to create new bindings\n\t\t\t\t\t\t// for objects that are cached, the binding may\n\t\t\t\t\t\t// or may not exist\n\n\t\t\t\t\t\tbinding = new PropertyBinding(\n\t\t\t\t\t\t\t\tobject, paths[ j ], parsedPaths[ j ] );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbindingsForPath[ firstActiveIndex ] = binding;\n\n\t\t\t\t}\n\n\t\t\t} else if ( objects[ index ] !== knownObject) {\n\n\t\t\t\tconsole.error( \"Different objects with the same UUID \" +\n\t\t\t\t\t\t\"detected. Clean the caches or recreate your \" +\n\t\t\t\t\t\t\"infrastructure when reloading scenes...\" );\n\n\t\t\t} // else the object is already where we want it to be\n\n\t\t} // for arguments\n\n\t\tthis.nCachedObjects_ = nCachedObjects;\n\n\t},\n\n\tremove: function( var_args ) {\n\n\t\tvar objects = this._objects,\n\t\t\tnCachedObjects = this.nCachedObjects_,\n\t\t\tindicesByUUID = this._indicesByUUID,\n\t\t\tbindings = this._bindings,\n\t\t\tnBindings = bindings.length;\n\n\t\tfor ( var i = 0, n = arguments.length; i !== n; ++ i ) {\n\n\t\t\tvar object = arguments[ i ],\n\t\t\t\tuuid = object.uuid,\n\t\t\t\tindex = indicesByUUID[ uuid ];\n\n\t\t\tif ( index !== undefined && index >= nCachedObjects ) {\n\n\t\t\t\t// move existing object into the CACHED region\n\n\t\t\t\tvar lastCachedIndex = nCachedObjects ++,\n\t\t\t\t\tfirstActiveObject = objects[ lastCachedIndex ];\n\n\t\t\t\tindicesByUUID[ firstActiveObject.uuid ] = index;\n\t\t\t\tobjects[ index ] = firstActiveObject;\n\n\t\t\t\tindicesByUUID[ uuid ] = lastCachedIndex;\n\t\t\t\tobjects[ lastCachedIndex ] = object;\n\n\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\tfor ( var j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\tvar bindingsForPath = bindings[ j ],\n\t\t\t\t\t\tfirstActive = bindingsForPath[ lastCachedIndex ],\n\t\t\t\t\t\tbinding = bindingsForPath[ index ];\n\n\t\t\t\t\tbindingsForPath[ index ] = firstActive;\n\t\t\t\t\tbindingsForPath[ lastCachedIndex ] = binding;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} // for arguments\n\n\t\tthis.nCachedObjects_ = nCachedObjects;\n\n\t},\n\n\t// remove & forget\n\tuncache: function( var_args ) {\n\n\t\tvar objects = this._objects,\n\t\t\tnObjects = objects.length,\n\t\t\tnCachedObjects = this.nCachedObjects_,\n\t\t\tindicesByUUID = this._indicesByUUID,\n\t\t\tbindings = this._bindings,\n\t\t\tnBindings = bindings.length;\n\n\t\tfor ( var i = 0, n = arguments.length; i !== n; ++ i ) {\n\n\t\t\tvar object = arguments[ i ],\n\t\t\t\tuuid = object.uuid,\n\t\t\t\tindex = indicesByUUID[ uuid ];\n\n\t\t\tif ( index !== undefined ) {\n\n\t\t\t\tdelete indicesByUUID[ uuid ];\n\n\t\t\t\tif ( index < nCachedObjects ) {\n\n\t\t\t\t\t// object is cached, shrink the CACHED region\n\n\t\t\t\t\tvar firstActiveIndex = -- nCachedObjects,\n\t\t\t\t\t\tlastCachedObject = objects[ firstActiveIndex ],\n\t\t\t\t\t\tlastIndex = -- nObjects,\n\t\t\t\t\t\tlastObject = objects[ lastIndex ];\n\n\t\t\t\t\t// last cached object takes this object's place\n\t\t\t\t\tindicesByUUID[ lastCachedObject.uuid ] = index;\n\t\t\t\t\tobjects[ index ] = lastCachedObject;\n\n\t\t\t\t\t// last object goes to the activated slot and pop\n\t\t\t\t\tindicesByUUID[ lastObject.uuid ] = firstActiveIndex;\n\t\t\t\t\tobjects[ firstActiveIndex ] = lastObject;\n\t\t\t\t\tobjects.pop();\n\n\t\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\t\tfor ( var j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\t\tvar bindingsForPath = bindings[ j ],\n\t\t\t\t\t\t\tlastCached = bindingsForPath[ firstActiveIndex ],\n\t\t\t\t\t\t\tlast = bindingsForPath[ lastIndex ];\n\n\t\t\t\t\t\tbindingsForPath[ index ] = lastCached;\n\t\t\t\t\t\tbindingsForPath[ firstActiveIndex ] = last;\n\t\t\t\t\t\tbindingsForPath.pop();\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// object is active, just swap with the last and pop\n\n\t\t\t\t\tvar lastIndex = -- nObjects,\n\t\t\t\t\t\tlastObject = objects[ lastIndex ];\n\n\t\t\t\t\tindicesByUUID[ lastObject.uuid ] = index;\n\t\t\t\t\tobjects[ index ] = lastObject;\n\t\t\t\t\tobjects.pop();\n\n\t\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\t\tfor ( var j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\t\tvar bindingsForPath = bindings[ j ];\n\n\t\t\t\t\t\tbindingsForPath[ index ] = bindingsForPath[ lastIndex ];\n\t\t\t\t\t\tbindingsForPath.pop();\n\n\t\t\t\t\t}\n\n\t\t\t\t} // cached or active\n\n\t\t\t} // if object is known\n\n\t\t} // for arguments\n\n\t\tthis.nCachedObjects_ = nCachedObjects;\n\n\t},\n\n\t// Internal interface used by befriended PropertyBinding.Composite:\n\n\tsubscribe_: function( path, parsedPath ) {\n\t\t// returns an array of bindings for the given path that is changed\n\t\t// according to the contained objects in the group\n\n\t\tvar indicesByPath = this._bindingsIndicesByPath,\n\t\t\tindex = indicesByPath[ path ],\n\t\t\tbindings = this._bindings;\n\n\t\tif ( index !== undefined ) return bindings[ index ];\n\n\t\tvar paths = this._paths,\n\t\t\tparsedPaths = this._parsedPaths,\n\t\t\tobjects = this._objects,\n\t\t\tnObjects = objects.length,\n\t\t\tnCachedObjects = this.nCachedObjects_,\n\t\t\tbindingsForPath = new Array( nObjects );\n\n\t\tindex = bindings.length;\n\n\t\tindicesByPath[ path ] = index;\n\n\t\tpaths.push( path );\n\t\tparsedPaths.push( parsedPath );\n\t\tbindings.push( bindingsForPath );\n\n\t\tfor ( var i = nCachedObjects,\n\t\t\t\tn = objects.length; i !== n; ++ i ) {\n\n\t\t\tvar object = objects[ i ];\n\n\t\t\tbindingsForPath[ i ] =\n\t\t\t\t\tnew PropertyBinding( object, path, parsedPath );\n\n\t\t}\n\n\t\treturn bindingsForPath;\n\n\t},\n\n\tunsubscribe_: function( path ) {\n\t\t// tells the group to forget about a property path and no longer\n\t\t// update the array previously obtained with 'subscribe_'\n\n\t\tvar indicesByPath = this._bindingsIndicesByPath,\n\t\t\tindex = indicesByPath[ path ];\n\n\t\tif ( index !== undefined ) {\n\n\t\t\tvar paths = this._paths,\n\t\t\t\tparsedPaths = this._parsedPaths,\n\t\t\t\tbindings = this._bindings,\n\t\t\t\tlastBindingsIndex = bindings.length - 1,\n\t\t\t\tlastBindings = bindings[ lastBindingsIndex ],\n\t\t\t\tlastBindingsPath = path[ lastBindingsIndex ];\n\n\t\t\tindicesByPath[ lastBindingsPath ] = index;\n\n\t\t\tbindings[ index ] = lastBindings;\n\t\t\tbindings.pop();\n\n\t\t\tparsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];\n\t\t\tparsedPaths.pop();\n\n\t\t\tpaths[ index ] = paths[ lastBindingsIndex ];\n\t\t\tpaths.pop();\n\n\t\t}\n\n\t}\n\n};\n\n/**\n *\n * Action provided by AnimationMixer for scheduling clip playback on specific\n * objects.\n *\n * @author Ben Houston / http://clara.io/\n * @author David Sarno / http://lighthaus.us/\n * @author tschw\n *\n */\n\nfunction AnimationAction( mixer, clip, localRoot ) {\n\n\tthis._mixer = mixer;\n\tthis._clip = clip;\n\tthis._localRoot = localRoot || null;\n\n\tvar tracks = clip.tracks,\n\t\tnTracks = tracks.length,\n\t\tinterpolants = new Array( nTracks );\n\n\tvar interpolantSettings = {\n\t\t\tendingStart: \tZeroCurvatureEnding,\n\t\t\tendingEnd:\t\tZeroCurvatureEnding\n\t};\n\n\tfor ( var i = 0; i !== nTracks; ++ i ) {\n\n\t\tvar interpolant = tracks[ i ].createInterpolant( null );\n\t\tinterpolants[ i ] = interpolant;\n\t\tinterpolant.settings = interpolantSettings;\n\n\t}\n\n\tthis._interpolantSettings = interpolantSettings;\n\n\tthis._interpolants = interpolants;\t// bound by the mixer\n\n\t// inside: PropertyMixer (managed by the mixer)\n\tthis._propertyBindings = new Array( nTracks );\n\n\tthis._cacheIndex = null;\t\t\t// for the memory manager\n\tthis._byClipCacheIndex = null;\t\t// for the memory manager\n\n\tthis._timeScaleInterpolant = null;\n\tthis._weightInterpolant = null;\n\n\tthis.loop = LoopRepeat;\n\tthis._loopCount = -1;\n\n\t// global mixer time when the action is to be started\n\t// it's set back to 'null' upon start of the action\n\tthis._startTime = null;\n\n\t// scaled local time of the action\n\t// gets clamped or wrapped to 0..clip.duration according to loop\n\tthis.time = 0;\n\n\tthis.timeScale = 1;\n\tthis._effectiveTimeScale = 1;\n\n\tthis.weight = 1;\n\tthis._effectiveWeight = 1;\n\n\tthis.repetitions = Infinity; \t\t// no. of repetitions when looping\n\n\tthis.paused = false;\t\t\t\t// false -> zero effective time scale\n\tthis.enabled = true;\t\t\t\t// true -> zero effective weight\n\n\tthis.clampWhenFinished \t= false;\t// keep feeding the last frame?\n\n\tthis.zeroSlopeAtStart \t= true;\t\t// for smooth interpolation w/o separate\n\tthis.zeroSlopeAtEnd\t\t= true;\t\t// clips for start, loop and end\n\n}\n\nAnimationAction.prototype = {\n\n\tconstructor: AnimationAction,\n\n\t// State & Scheduling\n\n\tplay: function() {\n\n\t\tthis._mixer._activateAction( this );\n\n\t\treturn this;\n\n\t},\n\n\tstop: function() {\n\n\t\tthis._mixer._deactivateAction( this );\n\n\t\treturn this.reset();\n\n\t},\n\n\treset: function() {\n\n\t\tthis.paused = false;\n\t\tthis.enabled = true;\n\n\t\tthis.time = 0;\t\t\t// restart clip\n\t\tthis._loopCount = -1;\t// forget previous loops\n\t\tthis._startTime = null;\t// forget scheduling\n\n\t\treturn this.stopFading().stopWarping();\n\n\t},\n\n\tisRunning: function() {\n\n\t\treturn this.enabled && ! this.paused && this.timeScale !== 0 &&\n\t\t\t\tthis._startTime === null && this._mixer._isActiveAction( this );\n\n\t},\n\n\t// return true when play has been called\n\tisScheduled: function() {\n\n\t\treturn this._mixer._isActiveAction( this );\n\n\t},\n\n\tstartAt: function( time ) {\n\n\t\tthis._startTime = time;\n\n\t\treturn this;\n\n\t},\n\n\tsetLoop: function( mode, repetitions ) {\n\n\t\tthis.loop = mode;\n\t\tthis.repetitions = repetitions;\n\n\t\treturn this;\n\n\t},\n\n\t// Weight\n\n\t// set the weight stopping any scheduled fading\n\t// although .enabled = false yields an effective weight of zero, this\n\t// method does *not* change .enabled, because it would be confusing\n\tsetEffectiveWeight: function( weight ) {\n\n\t\tthis.weight = weight;\n\n\t\t// note: same logic as when updated at runtime\n\t\tthis._effectiveWeight = this.enabled ? weight : 0;\n\n\t\treturn this.stopFading();\n\n\t},\n\n\t// return the weight considering fading and .enabled\n\tgetEffectiveWeight: function() {\n\n\t\treturn this._effectiveWeight;\n\n\t},\n\n\tfadeIn: function( duration ) {\n\n\t\treturn this._scheduleFading( duration, 0, 1 );\n\n\t},\n\n\tfadeOut: function( duration ) {\n\n\t\treturn this._scheduleFading( duration, 1, 0 );\n\n\t},\n\n\tcrossFadeFrom: function( fadeOutAction, duration, warp ) {\n\n\t\tfadeOutAction.fadeOut( duration );\n\t\tthis.fadeIn( duration );\n\n\t\tif( warp ) {\n\n\t\t\tvar fadeInDuration = this._clip.duration,\n\t\t\t\tfadeOutDuration = fadeOutAction._clip.duration,\n\n\t\t\t\tstartEndRatio = fadeOutDuration / fadeInDuration,\n\t\t\t\tendStartRatio = fadeInDuration / fadeOutDuration;\n\n\t\t\tfadeOutAction.warp( 1.0, startEndRatio, duration );\n\t\t\tthis.warp( endStartRatio, 1.0, duration );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tcrossFadeTo: function( fadeInAction, duration, warp ) {\n\n\t\treturn fadeInAction.crossFadeFrom( this, duration, warp );\n\n\t},\n\n\tstopFading: function() {\n\n\t\tvar weightInterpolant = this._weightInterpolant;\n\n\t\tif ( weightInterpolant !== null ) {\n\n\t\t\tthis._weightInterpolant = null;\n\t\t\tthis._mixer._takeBackControlInterpolant( weightInterpolant );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\t// Time Scale Control\n\n\t// set the weight stopping any scheduled warping\n\t// although .paused = true yields an effective time scale of zero, this\n\t// method does *not* change .paused, because it would be confusing\n\tsetEffectiveTimeScale: function( timeScale ) {\n\n\t\tthis.timeScale = timeScale;\n\t\tthis._effectiveTimeScale = this.paused ? 0 :timeScale;\n\n\t\treturn this.stopWarping();\n\n\t},\n\n\t// return the time scale considering warping and .paused\n\tgetEffectiveTimeScale: function() {\n\n\t\treturn this._effectiveTimeScale;\n\n\t},\n\n\tsetDuration: function( duration ) {\n\n\t\tthis.timeScale = this._clip.duration / duration;\n\n\t\treturn this.stopWarping();\n\n\t},\n\n\tsyncWith: function( action ) {\n\n\t\tthis.time = action.time;\n\t\tthis.timeScale = action.timeScale;\n\n\t\treturn this.stopWarping();\n\n\t},\n\n\thalt: function( duration ) {\n\n\t\treturn this.warp( this._effectiveTimeScale, 0, duration );\n\n\t},\n\n\twarp: function( startTimeScale, endTimeScale, duration ) {\n\n\t\tvar mixer = this._mixer, now = mixer.time,\n\t\t\tinterpolant = this._timeScaleInterpolant,\n\n\t\t\ttimeScale = this.timeScale;\n\n\t\tif ( interpolant === null ) {\n\n\t\t\tinterpolant = mixer._lendControlInterpolant();\n\t\t\tthis._timeScaleInterpolant = interpolant;\n\n\t\t}\n\n\t\tvar times = interpolant.parameterPositions,\n\t\t\tvalues = interpolant.sampleValues;\n\n\t\ttimes[ 0 ] = now;\n\t\ttimes[ 1 ] = now + duration;\n\n\t\tvalues[ 0 ] = startTimeScale / timeScale;\n\t\tvalues[ 1 ] = endTimeScale / timeScale;\n\n\t\treturn this;\n\n\t},\n\n\tstopWarping: function() {\n\n\t\tvar timeScaleInterpolant = this._timeScaleInterpolant;\n\n\t\tif ( timeScaleInterpolant !== null ) {\n\n\t\t\tthis._timeScaleInterpolant = null;\n\t\t\tthis._mixer._takeBackControlInterpolant( timeScaleInterpolant );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\t// Object Accessors\n\n\tgetMixer: function() {\n\n\t\treturn this._mixer;\n\n\t},\n\n\tgetClip: function() {\n\n\t\treturn this._clip;\n\n\t},\n\n\tgetRoot: function() {\n\n\t\treturn this._localRoot || this._mixer._root;\n\n\t},\n\n\t// Interna\n\n\t_update: function( time, deltaTime, timeDirection, accuIndex ) {\n\t\t// called by the mixer\n\n\t\tvar startTime = this._startTime;\n\n\t\tif ( startTime !== null ) {\n\n\t\t\t// check for scheduled start of action\n\n\t\t\tvar timeRunning = ( time - startTime ) * timeDirection;\n\t\t\tif ( timeRunning < 0 || timeDirection === 0 ) {\n\n\t\t\t\treturn; // yet to come / don't decide when delta = 0\n\n\t\t\t}\n\n\t\t\t// start\n\n\t\t\tthis._startTime = null; // unschedule\n\t\t\tdeltaTime = timeDirection * timeRunning;\n\n\t\t}\n\n\t\t// apply time scale and advance time\n\n\t\tdeltaTime *= this._updateTimeScale( time );\n\t\tvar clipTime = this._updateTime( deltaTime );\n\n\t\t// note: _updateTime may disable the action resulting in\n\t\t// an effective weight of 0\n\n\t\tvar weight = this._updateWeight( time );\n\n\t\tif ( weight > 0 ) {\n\n\t\t\tvar interpolants = this._interpolants;\n\t\t\tvar propertyMixers = this._propertyBindings;\n\n\t\t\tfor ( var j = 0, m = interpolants.length; j !== m; ++ j ) {\n\n\t\t\t\tinterpolants[ j ].evaluate( clipTime );\n\t\t\t\tpropertyMixers[ j ].accumulate( accuIndex, weight );\n\n\t\t\t}\n\n\t\t}\n\n\t},\n\n\t_updateWeight: function( time ) {\n\n\t\tvar weight = 0;\n\n\t\tif ( this.enabled ) {\n\n\t\t\tweight = this.weight;\n\t\t\tvar interpolant = this._weightInterpolant;\n\n\t\t\tif ( interpolant !== null ) {\n\n\t\t\t\tvar interpolantValue = interpolant.evaluate( time )[ 0 ];\n\n\t\t\t\tweight *= interpolantValue;\n\n\t\t\t\tif ( time > interpolant.parameterPositions[ 1 ] ) {\n\n\t\t\t\t\tthis.stopFading();\n\n\t\t\t\t\tif ( interpolantValue === 0 ) {\n\n\t\t\t\t\t\t// faded out, disable\n\t\t\t\t\t\tthis.enabled = false;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis._effectiveWeight = weight;\n\t\treturn weight;\n\n\t},\n\n\t_updateTimeScale: function( time ) {\n\n\t\tvar timeScale = 0;\n\n\t\tif ( ! this.paused ) {\n\n\t\t\ttimeScale = this.timeScale;\n\n\t\t\tvar interpolant = this._timeScaleInterpolant;\n\n\t\t\tif ( interpolant !== null ) {\n\n\t\t\t\tvar interpolantValue = interpolant.evaluate( time )[ 0 ];\n\n\t\t\t\ttimeScale *= interpolantValue;\n\n\t\t\t\tif ( time > interpolant.parameterPositions[ 1 ] ) {\n\n\t\t\t\t\tthis.stopWarping();\n\n\t\t\t\t\tif ( timeScale === 0 ) {\n\n\t\t\t\t\t\t// motion has halted, pause\n\t\t\t\t\t\tthis.paused = true;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// warp done - apply final time scale\n\t\t\t\t\t\tthis.timeScale = timeScale;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis._effectiveTimeScale = timeScale;\n\t\treturn timeScale;\n\n\t},\n\n\t_updateTime: function( deltaTime ) {\n\n\t\tvar time = this.time + deltaTime;\n\n\t\tif ( deltaTime === 0 ) return time;\n\n\t\tvar duration = this._clip.duration,\n\n\t\t\tloop = this.loop,\n\t\t\tloopCount = this._loopCount;\n\n\t\tif ( loop === LoopOnce ) {\n\n\t\t\tif ( loopCount === -1 ) {\n\t\t\t\t// just started\n\n\t\t\t\tthis._loopCount = 0;\n\t\t\t\tthis._setEndings( true, true, false );\n\n\t\t\t}\n\n\t\t\thandle_stop: {\n\n\t\t\t\tif ( time >= duration ) {\n\n\t\t\t\t\ttime = duration;\n\n\t\t\t\t} else if ( time < 0 ) {\n\n\t\t\t\t\ttime = 0;\n\n\t\t\t\t} else break handle_stop;\n\n\t\t\t\tif ( this.clampWhenFinished ) this.paused = true;\n\t\t\t\telse this.enabled = false;\n\n\t\t\t\tthis._mixer.dispatchEvent( {\n\t\t\t\t\ttype: 'finished', action: this,\n\t\t\t\t\tdirection: deltaTime < 0 ? -1 : 1\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t} else { // repetitive Repeat or PingPong\n\n\t\t\tvar pingPong = ( loop === LoopPingPong );\n\n\t\t\tif ( loopCount === -1 ) {\n\t\t\t\t// just started\n\n\t\t\t\tif ( deltaTime >= 0 ) {\n\n\t\t\t\t\tloopCount = 0;\n\n\t\t\t\t\tthis._setEndings(\n\t\t\t\t\t\t\ttrue, this.repetitions === 0, pingPong );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// when looping in reverse direction, the initial\n\t\t\t\t\t// transition through zero counts as a repetition,\n\t\t\t\t\t// so leave loopCount at -1\n\n\t\t\t\t\tthis._setEndings(\n\t\t\t\t\t\t\tthis.repetitions === 0, true, pingPong );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( time >= duration || time < 0 ) {\n\t\t\t\t// wrap around\n\n\t\t\t\tvar loopDelta = Math.floor( time / duration ); // signed\n\t\t\t\ttime -= duration * loopDelta;\n\n\t\t\t\tloopCount += Math.abs( loopDelta );\n\n\t\t\t\tvar pending = this.repetitions - loopCount;\n\n\t\t\t\tif ( pending < 0 ) {\n\t\t\t\t\t// have to stop (switch state, clamp time, fire event)\n\n\t\t\t\t\tif ( this.clampWhenFinished ) this.paused = true;\n\t\t\t\t\telse this.enabled = false;\n\n\t\t\t\t\ttime = deltaTime > 0 ? duration : 0;\n\n\t\t\t\t\tthis._mixer.dispatchEvent( {\n\t\t\t\t\t\ttype: 'finished', action: this,\n\t\t\t\t\t\tdirection: deltaTime > 0 ? 1 : -1\n\t\t\t\t\t} );\n\n\t\t\t\t} else {\n\t\t\t\t\t// keep running\n\n\t\t\t\t\tif ( pending === 0 ) {\n\t\t\t\t\t\t// entering the last round\n\n\t\t\t\t\t\tvar atStart = deltaTime < 0;\n\t\t\t\t\t\tthis._setEndings( atStart, ! atStart, pingPong );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tthis._setEndings( false, false, pingPong );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._loopCount = loopCount;\n\n\t\t\t\t\tthis._mixer.dispatchEvent( {\n\t\t\t\t\t\ttype: 'loop', action: this, loopDelta: loopDelta\n\t\t\t\t\t} );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( pingPong && ( loopCount & 1 ) === 1 ) {\n\t\t\t\t// invert time for the \"pong round\"\n\n\t\t\t\tthis.time = time;\n\t\t\t\treturn duration - time;\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.time = time;\n\t\treturn time;\n\n\t},\n\n\t_setEndings: function( atStart, atEnd, pingPong ) {\n\n\t\tvar settings = this._interpolantSettings;\n\n\t\tif ( pingPong ) {\n\n\t\t\tsettings.endingStart \t= ZeroSlopeEnding;\n\t\t\tsettings.endingEnd\t\t= ZeroSlopeEnding;\n\n\t\t} else {\n\n\t\t\t// assuming for LoopOnce atStart == atEnd == true\n\n\t\t\tif ( atStart ) {\n\n\t\t\t\tsettings.endingStart = this.zeroSlopeAtStart ?\n\t\t\t\t\t\tZeroSlopeEnding : ZeroCurvatureEnding;\n\n\t\t\t} else {\n\n\t\t\t\tsettings.endingStart = WrapAroundEnding;\n\n\t\t\t}\n\n\t\t\tif ( atEnd ) {\n\n\t\t\t\tsettings.endingEnd = this.zeroSlopeAtEnd ?\n\t\t\t\t\t\tZeroSlopeEnding : ZeroCurvatureEnding;\n\n\t\t\t} else {\n\n\t\t\t\tsettings.endingEnd \t = WrapAroundEnding;\n\n\t\t\t}\n\n\t\t}\n\n\t},\n\n\t_scheduleFading: function( duration, weightNow, weightThen ) {\n\n\t\tvar mixer = this._mixer, now = mixer.time,\n\t\t\tinterpolant = this._weightInterpolant;\n\n\t\tif ( interpolant === null ) {\n\n\t\t\tinterpolant = mixer._lendControlInterpolant();\n\t\t\tthis._weightInterpolant = interpolant;\n\n\t\t}\n\n\t\tvar times = interpolant.parameterPositions,\n\t\t\tvalues = interpolant.sampleValues;\n\n\t\ttimes[ 0 ] = now; \t\t\t\tvalues[ 0 ] = weightNow;\n\t\ttimes[ 1 ] = now + duration;\tvalues[ 1 ] = weightThen;\n\n\t\treturn this;\n\n\t}\n\n};\n\n/**\n *\n * Player for AnimationClips.\n *\n *\n * @author Ben Houston / http://clara.io/\n * @author David Sarno / http://lighthaus.us/\n * @author tschw\n */\n\nfunction AnimationMixer( root ) {\n\n\tthis._root = root;\n\tthis._initMemoryManager();\n\tthis._accuIndex = 0;\n\n\tthis.time = 0;\n\n\tthis.timeScale = 1.0;\n\n}\n\nAnimationMixer.prototype = {\n\n\tconstructor: AnimationMixer,\n\n\t// return an action for a clip optionally using a custom root target\n\t// object (this method allocates a lot of dynamic memory in case a\n\t// previously unknown clip/root combination is specified)\n\tclipAction: function ( clip, optionalRoot ) {\n\n\t\tvar root = optionalRoot || this._root,\n\t\t\trootUuid = root.uuid,\n\n\t\t\tclipObject = typeof clip === 'string' ?\n\t\t\t\t\tAnimationClip.findByName( root, clip ) : clip,\n\n\t\t\tclipUuid = clipObject !== null ? clipObject.uuid : clip,\n\n\t\t\tactionsForClip = this._actionsByClip[ clipUuid ],\n\t\t\tprototypeAction = null;\n\n\t\tif ( actionsForClip !== undefined ) {\n\n\t\t\tvar existingAction =\n\t\t\t\t\tactionsForClip.actionByRoot[ rootUuid ];\n\n\t\t\tif ( existingAction !== undefined ) {\n\n\t\t\t\treturn existingAction;\n\n\t\t\t}\n\n\t\t\t// we know the clip, so we don't have to parse all\n\t\t\t// the bindings again but can just copy\n\t\t\tprototypeAction = actionsForClip.knownActions[ 0 ];\n\n\t\t\t// also, take the clip from the prototype action\n\t\t\tif ( clipObject === null )\n\t\t\t\tclipObject = prototypeAction._clip;\n\n\t\t}\n\n\t\t// clip must be known when specified via string\n\t\tif ( clipObject === null ) return null;\n\n\t\t// allocate all resources required to run it\n\t\tvar newAction = new AnimationAction( this, clipObject, optionalRoot );\n\n\t\tthis._bindAction( newAction, prototypeAction );\n\n\t\t// and make the action known to the memory manager\n\t\tthis._addInactiveAction( newAction, clipUuid, rootUuid );\n\n\t\treturn newAction;\n\n\t},\n\n\t// get an existing action\n\texistingAction: function ( clip, optionalRoot ) {\n\n\t\tvar root = optionalRoot || this._root,\n\t\t\trootUuid = root.uuid,\n\n\t\t\tclipObject = typeof clip === 'string' ?\n\t\t\t\t\tAnimationClip.findByName( root, clip ) : clip,\n\n\t\t\tclipUuid = clipObject ? clipObject.uuid : clip,\n\n\t\t\tactionsForClip = this._actionsByClip[ clipUuid ];\n\n\t\tif ( actionsForClip !== undefined ) {\n\n\t\t\treturn actionsForClip.actionByRoot[ rootUuid ] || null;\n\n\t\t}\n\n\t\treturn null;\n\n\t},\n\n\t// deactivates all previously scheduled actions\n\tstopAllAction: function () {\n\n\t\tvar actions = this._actions,\n\t\t\tnActions = this._nActiveActions,\n\t\t\tbindings = this._bindings,\n\t\t\tnBindings = this._nActiveBindings;\n\n\t\tthis._nActiveActions = 0;\n\t\tthis._nActiveBindings = 0;\n\n\t\tfor ( var i = 0; i !== nActions; ++ i ) {\n\n\t\t\tactions[ i ].reset();\n\n\t\t}\n\n\t\tfor ( var i = 0; i !== nBindings; ++ i ) {\n\n\t\t\tbindings[ i ].useCount = 0;\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\t// advance the time and update apply the animation\n\tupdate: function ( deltaTime ) {\n\n\t\tdeltaTime *= this.timeScale;\n\n\t\tvar actions = this._actions,\n\t\t\tnActions = this._nActiveActions,\n\n\t\t\ttime = this.time += deltaTime,\n\t\t\ttimeDirection = Math.sign( deltaTime ),\n\n\t\t\taccuIndex = this._accuIndex ^= 1;\n\n\t\t// run active actions\n\n\t\tfor ( var i = 0; i !== nActions; ++ i ) {\n\n\t\t\tvar action = actions[ i ];\n\n\t\t\tif ( action.enabled ) {\n\n\t\t\t\taction._update( time, deltaTime, timeDirection, accuIndex );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// update scene graph\n\n\t\tvar bindings = this._bindings,\n\t\t\tnBindings = this._nActiveBindings;\n\n\t\tfor ( var i = 0; i !== nBindings; ++ i ) {\n\n\t\t\tbindings[ i ].apply( accuIndex );\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\t// return this mixer's root target object\n\tgetRoot: function () {\n\n\t\treturn this._root;\n\n\t},\n\n\t// free all resources specific to a particular clip\n\tuncacheClip: function ( clip ) {\n\n\t\tvar actions = this._actions,\n\t\t\tclipUuid = clip.uuid,\n\t\t\tactionsByClip = this._actionsByClip,\n\t\t\tactionsForClip = actionsByClip[ clipUuid ];\n\n\t\tif ( actionsForClip !== undefined ) {\n\n\t\t\t// note: just calling _removeInactiveAction would mess up the\n\t\t\t// iteration state and also require updating the state we can\n\t\t\t// just throw away\n\n\t\t\tvar actionsToRemove = actionsForClip.knownActions;\n\n\t\t\tfor ( var i = 0, n = actionsToRemove.length; i !== n; ++ i ) {\n\n\t\t\t\tvar action = actionsToRemove[ i ];\n\n\t\t\t\tthis._deactivateAction( action );\n\n\t\t\t\tvar cacheIndex = action._cacheIndex,\n\t\t\t\t\tlastInactiveAction = actions[ actions.length - 1 ];\n\n\t\t\t\taction._cacheIndex = null;\n\t\t\t\taction._byClipCacheIndex = null;\n\n\t\t\t\tlastInactiveAction._cacheIndex = cacheIndex;\n\t\t\t\tactions[ cacheIndex ] = lastInactiveAction;\n\t\t\t\tactions.pop();\n\n\t\t\t\tthis._removeInactiveBindingsForAction( action );\n\n\t\t\t}\n\n\t\t\tdelete actionsByClip[ clipUuid ];\n\n\t\t}\n\n\t},\n\n\t// free all resources specific to a particular root target object\n\tuncacheRoot: function ( root ) {\n\n\t\tvar rootUuid = root.uuid,\n\t\t\tactionsByClip = this._actionsByClip;\n\n\t\tfor ( var clipUuid in actionsByClip ) {\n\n\t\t\tvar actionByRoot = actionsByClip[ clipUuid ].actionByRoot,\n\t\t\t\taction = actionByRoot[ rootUuid ];\n\n\t\t\tif ( action !== undefined ) {\n\n\t\t\t\tthis._deactivateAction( action );\n\t\t\t\tthis._removeInactiveAction( action );\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar bindingsByRoot = this._bindingsByRootAndName,\n\t\t\tbindingByName = bindingsByRoot[ rootUuid ];\n\n\t\tif ( bindingByName !== undefined ) {\n\n\t\t\tfor ( var trackName in bindingByName ) {\n\n\t\t\t\tvar binding = bindingByName[ trackName ];\n\t\t\t\tbinding.restoreOriginalState();\n\t\t\t\tthis._removeInactiveBinding( binding );\n\n\t\t\t}\n\n\t\t}\n\n\t},\n\n\t// remove a targeted clip from the cache\n\tuncacheAction: function ( clip, optionalRoot ) {\n\n\t\tvar action = this.existingAction( clip, optionalRoot );\n\n\t\tif ( action !== null ) {\n\n\t\t\tthis._deactivateAction( action );\n\t\t\tthis._removeInactiveAction( action );\n\n\t\t}\n\n\t}\n\n};\n\n// Implementation details:\n\nObject.assign( AnimationMixer.prototype, {\n\n\t_bindAction: function ( action, prototypeAction ) {\n\n\t\tvar root = action._localRoot || this._root,\n\t\t\ttracks = action._clip.tracks,\n\t\t\tnTracks = tracks.length,\n\t\t\tbindings = action._propertyBindings,\n\t\t\tinterpolants = action._interpolants,\n\t\t\trootUuid = root.uuid,\n\t\t\tbindingsByRoot = this._bindingsByRootAndName,\n\t\t\tbindingsByName = bindingsByRoot[ rootUuid ];\n\n\t\tif ( bindingsByName === undefined ) {\n\n\t\t\tbindingsByName = {};\n\t\t\tbindingsByRoot[ rootUuid ] = bindingsByName;\n\n\t\t}\n\n\t\tfor ( var i = 0; i !== nTracks; ++ i ) {\n\n\t\t\tvar track = tracks[ i ],\n\t\t\t\ttrackName = track.name,\n\t\t\t\tbinding = bindingsByName[ trackName ];\n\n\t\t\tif ( binding !== undefined ) {\n\n\t\t\t\tbindings[ i ] = binding;\n\n\t\t\t} else {\n\n\t\t\t\tbinding = bindings[ i ];\n\n\t\t\t\tif ( binding !== undefined ) {\n\n\t\t\t\t\t// existing binding, make sure the cache knows\n\n\t\t\t\t\tif ( binding._cacheIndex === null ) {\n\n\t\t\t\t\t\t++ binding.referenceCount;\n\t\t\t\t\t\tthis._addInactiveBinding( binding, rootUuid, trackName );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tcontinue;\n\n\t\t\t\t}\n\n\t\t\t\tvar path = prototypeAction && prototypeAction.\n\t\t\t\t\t\t_propertyBindings[ i ].binding.parsedPath;\n\n\t\t\t\tbinding = new PropertyMixer(\n\t\t\t\t\t\tPropertyBinding.create( root, trackName, path ),\n\t\t\t\t\t\ttrack.ValueTypeName, track.getValueSize() );\n\n\t\t\t\t++ binding.referenceCount;\n\t\t\t\tthis._addInactiveBinding( binding, rootUuid, trackName );\n\n\t\t\t\tbindings[ i ] = binding;\n\n\t\t\t}\n\n\t\t\tinterpolants[ i ].resultBuffer = binding.buffer;\n\n\t\t}\n\n\t},\n\n\t_activateAction: function ( action ) {\n\n\t\tif ( ! this._isActiveAction( action ) ) {\n\n\t\t\tif ( action._cacheIndex === null ) {\n\n\t\t\t\t// this action has been forgotten by the cache, but the user\n\t\t\t\t// appears to be still using it -> rebind\n\n\t\t\t\tvar rootUuid = ( action._localRoot || this._root ).uuid,\n\t\t\t\t\tclipUuid = action._clip.uuid,\n\t\t\t\t\tactionsForClip = this._actionsByClip[ clipUuid ];\n\n\t\t\t\tthis._bindAction( action,\n\t\t\t\t\t\tactionsForClip && actionsForClip.knownActions[ 0 ] );\n\n\t\t\t\tthis._addInactiveAction( action, clipUuid, rootUuid );\n\n\t\t\t}\n\n\t\t\tvar bindings = action._propertyBindings;\n\n\t\t\t// increment reference counts / sort out state\n\t\t\tfor ( var i = 0, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\t\tvar binding = bindings[ i ];\n\n\t\t\t\tif ( binding.useCount ++ === 0 ) {\n\n\t\t\t\t\tthis._lendBinding( binding );\n\t\t\t\t\tbinding.saveOriginalState();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis._lendAction( action );\n\n\t\t}\n\n\t},\n\n\t_deactivateAction: function ( action ) {\n\n\t\tif ( this._isActiveAction( action ) ) {\n\n\t\t\tvar bindings = action._propertyBindings;\n\n\t\t\t// decrement reference counts / sort out state\n\t\t\tfor ( var i = 0, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\t\tvar binding = bindings[ i ];\n\n\t\t\t\tif ( -- binding.useCount === 0 ) {\n\n\t\t\t\t\tbinding.restoreOriginalState();\n\t\t\t\t\tthis._takeBackBinding( binding );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis._takeBackAction( action );\n\n\t\t}\n\n\t},\n\n\t// Memory manager\n\n\t_initMemoryManager: function () {\n\n\t\tthis._actions = []; // 'nActiveActions' followed by inactive ones\n\t\tthis._nActiveActions = 0;\n\n\t\tthis._actionsByClip = {};\n\t\t// inside:\n\t\t// {\n\t\t// \t\tknownActions: Array< AnimationAction >\t- used as prototypes\n\t\t// \t\tactionByRoot: AnimationAction\t\t\t- lookup\n\t\t// }\n\n\n\t\tthis._bindings = []; // 'nActiveBindings' followed by inactive ones\n\t\tthis._nActiveBindings = 0;\n\n\t\tthis._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer >\n\n\n\t\tthis._controlInterpolants = []; // same game as above\n\t\tthis._nActiveControlInterpolants = 0;\n\n\t\tvar scope = this;\n\n\t\tthis.stats = {\n\n\t\t\tactions: {\n\t\t\t\tget total() { return scope._actions.length; },\n\t\t\t\tget inUse() { return scope._nActiveActions; }\n\t\t\t},\n\t\t\tbindings: {\n\t\t\t\tget total() { return scope._bindings.length; },\n\t\t\t\tget inUse() { return scope._nActiveBindings; }\n\t\t\t},\n\t\t\tcontrolInterpolants: {\n\t\t\t\tget total() { return scope._controlInterpolants.length; },\n\t\t\t\tget inUse() { return scope._nActiveControlInterpolants; }\n\t\t\t}\n\n\t\t};\n\n\t},\n\n\t// Memory management for AnimationAction objects\n\n\t_isActiveAction: function ( action ) {\n\n\t\tvar index = action._cacheIndex;\n\t\treturn index !== null && index < this._nActiveActions;\n\n\t},\n\n\t_addInactiveAction: function ( action, clipUuid, rootUuid ) {\n\n\t\tvar actions = this._actions,\n\t\t\tactionsByClip = this._actionsByClip,\n\t\t\tactionsForClip = actionsByClip[ clipUuid ];\n\n\t\tif ( actionsForClip === undefined ) {\n\n\t\t\tactionsForClip = {\n\n\t\t\t\tknownActions: [ action ],\n\t\t\t\tactionByRoot: {}\n\n\t\t\t};\n\n\t\t\taction._byClipCacheIndex = 0;\n\n\t\t\tactionsByClip[ clipUuid ] = actionsForClip;\n\n\t\t} else {\n\n\t\t\tvar knownActions = actionsForClip.knownActions;\n\n\t\t\taction._byClipCacheIndex = knownActions.length;\n\t\t\tknownActions.push( action );\n\n\t\t}\n\n\t\taction._cacheIndex = actions.length;\n\t\tactions.push( action );\n\n\t\tactionsForClip.actionByRoot[ rootUuid ] = action;\n\n\t},\n\n\t_removeInactiveAction: function ( action ) {\n\n\t\tvar actions = this._actions,\n\t\t\tlastInactiveAction = actions[ actions.length - 1 ],\n\t\t\tcacheIndex = action._cacheIndex;\n\n\t\tlastInactiveAction._cacheIndex = cacheIndex;\n\t\tactions[ cacheIndex ] = lastInactiveAction;\n\t\tactions.pop();\n\n\t\taction._cacheIndex = null;\n\n\n\t\tvar clipUuid = action._clip.uuid,\n\t\t\tactionsByClip = this._actionsByClip,\n\t\t\tactionsForClip = actionsByClip[ clipUuid ],\n\t\t\tknownActionsForClip = actionsForClip.knownActions,\n\n\t\t\tlastKnownAction =\n\t\t\t\tknownActionsForClip[ knownActionsForClip.length - 1 ],\n\n\t\t\tbyClipCacheIndex = action._byClipCacheIndex;\n\n\t\tlastKnownAction._byClipCacheIndex = byClipCacheIndex;\n\t\tknownActionsForClip[ byClipCacheIndex ] = lastKnownAction;\n\t\tknownActionsForClip.pop();\n\n\t\taction._byClipCacheIndex = null;\n\n\n\t\tvar actionByRoot = actionsForClip.actionByRoot,\n\t\t\trootUuid = ( actions._localRoot || this._root ).uuid;\n\n\t\tdelete actionByRoot[ rootUuid ];\n\n\t\tif ( knownActionsForClip.length === 0 ) {\n\n\t\t\tdelete actionsByClip[ clipUuid ];\n\n\t\t}\n\n\t\tthis._removeInactiveBindingsForAction( action );\n\n\t},\n\n\t_removeInactiveBindingsForAction: function ( action ) {\n\n\t\tvar bindings = action._propertyBindings;\n\t\tfor ( var i = 0, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\tvar binding = bindings[ i ];\n\n\t\t\tif ( -- binding.referenceCount === 0 ) {\n\n\t\t\t\tthis._removeInactiveBinding( binding );\n\n\t\t\t}\n\n\t\t}\n\n\t},\n\n\t_lendAction: function ( action ) {\n\n\t\t// [ active actions | inactive actions ]\n\t\t// [ active actions >| inactive actions ]\n\t\t// s a\n\t\t// <-swap->\n\t\t// a s\n\n\t\tvar actions = this._actions,\n\t\t\tprevIndex = action._cacheIndex,\n\n\t\t\tlastActiveIndex = this._nActiveActions ++,\n\n\t\t\tfirstInactiveAction = actions[ lastActiveIndex ];\n\n\t\taction._cacheIndex = lastActiveIndex;\n\t\tactions[ lastActiveIndex ] = action;\n\n\t\tfirstInactiveAction._cacheIndex = prevIndex;\n\t\tactions[ prevIndex ] = firstInactiveAction;\n\n\t},\n\n\t_takeBackAction: function ( action ) {\n\n\t\t// [ active actions | inactive actions ]\n\t\t// [ active actions |< inactive actions ]\n\t\t// a s\n\t\t// <-swap->\n\t\t// s a\n\n\t\tvar actions = this._actions,\n\t\t\tprevIndex = action._cacheIndex,\n\n\t\t\tfirstInactiveIndex = -- this._nActiveActions,\n\n\t\t\tlastActiveAction = actions[ firstInactiveIndex ];\n\n\t\taction._cacheIndex = firstInactiveIndex;\n\t\tactions[ firstInactiveIndex ] = action;\n\n\t\tlastActiveAction._cacheIndex = prevIndex;\n\t\tactions[ prevIndex ] = lastActiveAction;\n\n\t},\n\n\t// Memory management for PropertyMixer objects\n\n\t_addInactiveBinding: function ( binding, rootUuid, trackName ) {\n\n\t\tvar bindingsByRoot = this._bindingsByRootAndName,\n\t\t\tbindingByName = bindingsByRoot[ rootUuid ],\n\n\t\t\tbindings = this._bindings;\n\n\t\tif ( bindingByName === undefined ) {\n\n\t\t\tbindingByName = {};\n\t\t\tbindingsByRoot[ rootUuid ] = bindingByName;\n\n\t\t}\n\n\t\tbindingByName[ trackName ] = binding;\n\n\t\tbinding._cacheIndex = bindings.length;\n\t\tbindings.push( binding );\n\n\t},\n\n\t_removeInactiveBinding: function ( binding ) {\n\n\t\tvar bindings = this._bindings,\n\t\t\tpropBinding = binding.binding,\n\t\t\trootUuid = propBinding.rootNode.uuid,\n\t\t\ttrackName = propBinding.path,\n\t\t\tbindingsByRoot = this._bindingsByRootAndName,\n\t\t\tbindingByName = bindingsByRoot[ rootUuid ],\n\n\t\t\tlastInactiveBinding = bindings[ bindings.length - 1 ],\n\t\t\tcacheIndex = binding._cacheIndex;\n\n\t\tlastInactiveBinding._cacheIndex = cacheIndex;\n\t\tbindings[ cacheIndex ] = lastInactiveBinding;\n\t\tbindings.pop();\n\n\t\tdelete bindingByName[ trackName ];\n\n\t\tremove_empty_map: {\n\n\t\t\tfor ( var _ in bindingByName ) break remove_empty_map;\n\n\t\t\tdelete bindingsByRoot[ rootUuid ];\n\n\t\t}\n\n\t},\n\n\t_lendBinding: function ( binding ) {\n\n\t\tvar bindings = this._bindings,\n\t\t\tprevIndex = binding._cacheIndex,\n\n\t\t\tlastActiveIndex = this._nActiveBindings ++,\n\n\t\t\tfirstInactiveBinding = bindings[ lastActiveIndex ];\n\n\t\tbinding._cacheIndex = lastActiveIndex;\n\t\tbindings[ lastActiveIndex ] = binding;\n\n\t\tfirstInactiveBinding._cacheIndex = prevIndex;\n\t\tbindings[ prevIndex ] = firstInactiveBinding;\n\n\t},\n\n\t_takeBackBinding: function ( binding ) {\n\n\t\tvar bindings = this._bindings,\n\t\t\tprevIndex = binding._cacheIndex,\n\n\t\t\tfirstInactiveIndex = -- this._nActiveBindings,\n\n\t\t\tlastActiveBinding = bindings[ firstInactiveIndex ];\n\n\t\tbinding._cacheIndex = firstInactiveIndex;\n\t\tbindings[ firstInactiveIndex ] = binding;\n\n\t\tlastActiveBinding._cacheIndex = prevIndex;\n\t\tbindings[ prevIndex ] = lastActiveBinding;\n\n\t},\n\n\n\t// Memory management of Interpolants for weight and time scale\n\n\t_lendControlInterpolant: function () {\n\n\t\tvar interpolants = this._controlInterpolants,\n\t\t\tlastActiveIndex = this._nActiveControlInterpolants ++,\n\t\t\tinterpolant = interpolants[ lastActiveIndex ];\n\n\t\tif ( interpolant === undefined ) {\n\n\t\t\tinterpolant = new LinearInterpolant(\n\t\t\t\t\tnew Float32Array( 2 ), new Float32Array( 2 ),\n\t\t\t\t\t\t1, this._controlInterpolantsResultBuffer );\n\n\t\t\tinterpolant.__cacheIndex = lastActiveIndex;\n\t\t\tinterpolants[ lastActiveIndex ] = interpolant;\n\n\t\t}\n\n\t\treturn interpolant;\n\n\t},\n\n\t_takeBackControlInterpolant: function ( interpolant ) {\n\n\t\tvar interpolants = this._controlInterpolants,\n\t\t\tprevIndex = interpolant.__cacheIndex,\n\n\t\t\tfirstInactiveIndex = -- this._nActiveControlInterpolants,\n\n\t\t\tlastActiveInterpolant = interpolants[ firstInactiveIndex ];\n\n\t\tinterpolant.__cacheIndex = firstInactiveIndex;\n\t\tinterpolants[ firstInactiveIndex ] = interpolant;\n\n\t\tlastActiveInterpolant.__cacheIndex = prevIndex;\n\t\tinterpolants[ prevIndex ] = lastActiveInterpolant;\n\n\t},\n\n\t_controlInterpolantsResultBuffer: new Float32Array( 1 )\n\n} );\n\nObject.assign( AnimationMixer.prototype, EventDispatcher.prototype );\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction Uniform( value ) {\n\n\tif ( typeof value === 'string' ) {\n\n\t\tconsole.warn( 'THREE.Uniform: Type parameter is no longer needed.' );\n\t\tvalue = arguments[ 1 ];\n\n\t}\n\n\tthis.value = value;\n\n}\n\nUniform.prototype.clone = function () {\n\n\treturn new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );\n\n};\n\n/**\n * @author benaadams / https://twitter.com/ben_a_adams\n */\n\nfunction InstancedBufferGeometry() {\n\n\tBufferGeometry.call( this );\n\n\tthis.type = 'InstancedBufferGeometry';\n\tthis.maxInstancedCount = undefined;\n\n}\n\nInstancedBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\nInstancedBufferGeometry.prototype.constructor = InstancedBufferGeometry;\n\nInstancedBufferGeometry.prototype.isInstancedBufferGeometry = true;\n\nInstancedBufferGeometry.prototype.addGroup = function ( start, count, materialIndex ) {\n\n\tthis.groups.push( {\n\n\t\tstart: start,\n\t\tcount: count,\n\t\tmaterialIndex: materialIndex\n\n\t} );\n\n};\n\nInstancedBufferGeometry.prototype.copy = function ( source ) {\n\n\tvar index = source.index;\n\n\tif ( index !== null ) {\n\n\t\tthis.setIndex( index.clone() );\n\n\t}\n\n\tvar attributes = source.attributes;\n\n\tfor ( var name in attributes ) {\n\n\t\tvar attribute = attributes[ name ];\n\t\tthis.addAttribute( name, attribute.clone() );\n\n\t}\n\n\tvar groups = source.groups;\n\n\tfor ( var i = 0, l = groups.length; i < l; i ++ ) {\n\n\t\tvar group = groups[ i ];\n\t\tthis.addGroup( group.start, group.count, group.materialIndex );\n\n\t}\n\n\treturn this;\n\n};\n\n/**\n * @author benaadams / https://twitter.com/ben_a_adams\n */\n\nfunction InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normalized ) {\n\n\tthis.uuid = _Math.generateUUID();\n\n\tthis.data = interleavedBuffer;\n\tthis.itemSize = itemSize;\n\tthis.offset = offset;\n\n\tthis.normalized = normalized === true;\n\n}\n\n\nInterleavedBufferAttribute.prototype = {\n\n\tconstructor: InterleavedBufferAttribute,\n\n\tisInterleavedBufferAttribute: true,\n\n\tget count() {\n\n\t\treturn this.data.count;\n\n\t},\n\n\tget array() {\n\n\t\treturn this.data.array;\n\n\t},\n\n\tsetX: function ( index, x ) {\n\n\t\tthis.data.array[ index * this.data.stride + this.offset ] = x;\n\n\t\treturn this;\n\n\t},\n\n\tsetY: function ( index, y ) {\n\n\t\tthis.data.array[ index * this.data.stride + this.offset + 1 ] = y;\n\n\t\treturn this;\n\n\t},\n\n\tsetZ: function ( index, z ) {\n\n\t\tthis.data.array[ index * this.data.stride + this.offset + 2 ] = z;\n\n\t\treturn this;\n\n\t},\n\n\tsetW: function ( index, w ) {\n\n\t\tthis.data.array[ index * this.data.stride + this.offset + 3 ] = w;\n\n\t\treturn this;\n\n\t},\n\n\tgetX: function ( index ) {\n\n\t\treturn this.data.array[ index * this.data.stride + this.offset ];\n\n\t},\n\n\tgetY: function ( index ) {\n\n\t\treturn this.data.array[ index * this.data.stride + this.offset + 1 ];\n\n\t},\n\n\tgetZ: function ( index ) {\n\n\t\treturn this.data.array[ index * this.data.stride + this.offset + 2 ];\n\n\t},\n\n\tgetW: function ( index ) {\n\n\t\treturn this.data.array[ index * this.data.stride + this.offset + 3 ];\n\n\t},\n\n\tsetXY: function ( index, x, y ) {\n\n\t\tindex = index * this.data.stride + this.offset;\n\n\t\tthis.data.array[ index + 0 ] = x;\n\t\tthis.data.array[ index + 1 ] = y;\n\n\t\treturn this;\n\n\t},\n\n\tsetXYZ: function ( index, x, y, z ) {\n\n\t\tindex = index * this.data.stride + this.offset;\n\n\t\tthis.data.array[ index + 0 ] = x;\n\t\tthis.data.array[ index + 1 ] = y;\n\t\tthis.data.array[ index + 2 ] = z;\n\n\t\treturn this;\n\n\t},\n\n\tsetXYZW: function ( index, x, y, z, w ) {\n\n\t\tindex = index * this.data.stride + this.offset;\n\n\t\tthis.data.array[ index + 0 ] = x;\n\t\tthis.data.array[ index + 1 ] = y;\n\t\tthis.data.array[ index + 2 ] = z;\n\t\tthis.data.array[ index + 3 ] = w;\n\n\t\treturn this;\n\n\t}\n\n};\n\n/**\n * @author benaadams / https://twitter.com/ben_a_adams\n */\n\nfunction InterleavedBuffer( array, stride ) {\n\n\tthis.uuid = _Math.generateUUID();\n\n\tthis.array = array;\n\tthis.stride = stride;\n\tthis.count = array !== undefined ? array.length / stride : 0;\n\n\tthis.dynamic = false;\n\tthis.updateRange = { offset: 0, count: - 1 };\n\n\tthis.onUploadCallback = function () {};\n\n\tthis.version = 0;\n\n}\n\nInterleavedBuffer.prototype = {\n\n\tconstructor: InterleavedBuffer,\n\n\tisInterleavedBuffer: true,\n\n\tset needsUpdate( value ) {\n\n\t\tif ( value === true ) this.version ++;\n\n\t},\n\n\tsetArray: function ( array ) {\n\n\t\tif ( Array.isArray( array ) ) {\n\n\t\t\tthrow new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );\n\n\t\t}\n\n\t\tthis.count = array !== undefined ? array.length / this.stride : 0;\n\t\tthis.array = array;\n\n\t},\n\n\tsetDynamic: function ( value ) {\n\n\t\tthis.dynamic = value;\n\n\t\treturn this;\n\n\t},\n\n\tcopy: function ( source ) {\n\n\t\tthis.array = new source.array.constructor( source.array );\n\t\tthis.count = source.count;\n\t\tthis.stride = source.stride;\n\t\tthis.dynamic = source.dynamic;\n\n\t\treturn this;\n\n\t},\n\n\tcopyAt: function ( index1, attribute, index2 ) {\n\n\t\tindex1 *= this.stride;\n\t\tindex2 *= attribute.stride;\n\n\t\tfor ( var i = 0, l = this.stride; i < l; i ++ ) {\n\n\t\t\tthis.array[ index1 + i ] = attribute.array[ index2 + i ];\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tset: function ( value, offset ) {\n\n\t\tif ( offset === undefined ) offset = 0;\n\n\t\tthis.array.set( value, offset );\n\n\t\treturn this;\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor().copy( this );\n\n\t},\n\n\tonUpload: function ( callback ) {\n\n\t\tthis.onUploadCallback = callback;\n\n\t\treturn this;\n\n\t}\n\n};\n\n/**\n * @author benaadams / https://twitter.com/ben_a_adams\n */\n\nfunction InstancedInterleavedBuffer( array, stride, meshPerAttribute ) {\n\n\tInterleavedBuffer.call( this, array, stride );\n\n\tthis.meshPerAttribute = meshPerAttribute || 1;\n\n}\n\nInstancedInterleavedBuffer.prototype = Object.create( InterleavedBuffer.prototype );\nInstancedInterleavedBuffer.prototype.constructor = InstancedInterleavedBuffer;\n\nInstancedInterleavedBuffer.prototype.isInstancedInterleavedBuffer = true;\n\nInstancedInterleavedBuffer.prototype.copy = function ( source ) {\n\n\tInterleavedBuffer.prototype.copy.call( this, source );\n\n\tthis.meshPerAttribute = source.meshPerAttribute;\n\n\treturn this;\n\n};\n\n/**\n * @author benaadams / https://twitter.com/ben_a_adams\n */\n\nfunction InstancedBufferAttribute( array, itemSize, meshPerAttribute ) {\n\n\tBufferAttribute.call( this, array, itemSize );\n\n\tthis.meshPerAttribute = meshPerAttribute || 1;\n\n}\n\nInstancedBufferAttribute.prototype = Object.create( BufferAttribute.prototype );\nInstancedBufferAttribute.prototype.constructor = InstancedBufferAttribute;\n\nInstancedBufferAttribute.prototype.isInstancedBufferAttribute = true;\n\nInstancedBufferAttribute.prototype.copy = function ( source ) {\n\n\tBufferAttribute.prototype.copy.call( this, source );\n\n\tthis.meshPerAttribute = source.meshPerAttribute;\n\n\treturn this;\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author bhouston / http://clara.io/\n * @author stephomi / http://stephaneginier.com/\n */\n\nfunction Raycaster( origin, direction, near, far ) {\n\n\tthis.ray = new Ray( origin, direction );\n\t// direction is assumed to be normalized (for accurate distance calculations)\n\n\tthis.near = near || 0;\n\tthis.far = far || Infinity;\n\n\tthis.params = {\n\t\tMesh: {},\n\t\tLine: {},\n\t\tLOD: {},\n\t\tPoints: { threshold: 1 },\n\t\tSprite: {}\n\t};\n\n\tObject.defineProperties( this.params, {\n\t\tPointCloud: {\n\t\t\tget: function () {\n\t\t\t\tconsole.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' );\n\t\t\t\treturn this.Points;\n\t\t\t}\n\t\t}\n\t} );\n\n}\n\nfunction ascSort( a, b ) {\n\n\treturn a.distance - b.distance;\n\n}\n\nfunction intersectObject( object, raycaster, intersects, recursive ) {\n\n\tif ( object.visible === false ) return;\n\n\tobject.raycast( raycaster, intersects );\n\n\tif ( recursive === true ) {\n\n\t\tvar children = object.children;\n\n\t\tfor ( var i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tintersectObject( children[ i ], raycaster, intersects, true );\n\n\t\t}\n\n\t}\n\n}\n\n//\n\nRaycaster.prototype = {\n\n\tconstructor: Raycaster,\n\n\tlinePrecision: 1,\n\n\tset: function ( origin, direction ) {\n\n\t\t// direction is assumed to be normalized (for accurate distance calculations)\n\n\t\tthis.ray.set( origin, direction );\n\n\t},\n\n\tsetFromCamera: function ( coords, camera ) {\n\n\t\tif ( (camera && camera.isPerspectiveCamera) ) {\n\n\t\t\tthis.ray.origin.setFromMatrixPosition( camera.matrixWorld );\n\t\t\tthis.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();\n\n\t\t} else if ( (camera && camera.isOrthographicCamera) ) {\n\n\t\t\tthis.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera\n\t\t\tthis.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );\n\n\t\t} else {\n\n\t\t\tconsole.error( 'THREE.Raycaster: Unsupported camera type.' );\n\n\t\t}\n\n\t},\n\n\tintersectObject: function ( object, recursive ) {\n\n\t\tvar intersects = [];\n\n\t\tintersectObject( object, this, intersects, recursive );\n\n\t\tintersects.sort( ascSort );\n\n\t\treturn intersects;\n\n\t},\n\n\tintersectObjects: function ( objects, recursive ) {\n\n\t\tvar intersects = [];\n\n\t\tif ( Array.isArray( objects ) === false ) {\n\n\t\t\tconsole.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' );\n\t\t\treturn intersects;\n\n\t\t}\n\n\t\tfor ( var i = 0, l = objects.length; i < l; i ++ ) {\n\n\t\t\tintersectObject( objects[ i ], this, intersects, recursive );\n\n\t\t}\n\n\t\tintersects.sort( ascSort );\n\n\t\treturn intersects;\n\n\t}\n\n};\n\n/**\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction Clock( autoStart ) {\n\n\tthis.autoStart = ( autoStart !== undefined ) ? autoStart : true;\n\n\tthis.startTime = 0;\n\tthis.oldTime = 0;\n\tthis.elapsedTime = 0;\n\n\tthis.running = false;\n\n}\n\nClock.prototype = {\n\n\tconstructor: Clock,\n\n\tstart: function () {\n\n\t\tthis.startTime = ( performance || Date ).now();\n\n\t\tthis.oldTime = this.startTime;\n\t\tthis.elapsedTime = 0;\n\t\tthis.running = true;\n\n\t},\n\n\tstop: function () {\n\n\t\tthis.getElapsedTime();\n\t\tthis.running = false;\n\n\t},\n\n\tgetElapsedTime: function () {\n\n\t\tthis.getDelta();\n\t\treturn this.elapsedTime;\n\n\t},\n\n\tgetDelta: function () {\n\n\t\tvar diff = 0;\n\n\t\tif ( this.autoStart && ! this.running ) {\n\n\t\t\tthis.start();\n\n\t\t}\n\n\t\tif ( this.running ) {\n\n\t\t\tvar newTime = ( performance || Date ).now();\n\n\t\t\tdiff = ( newTime - this.oldTime ) / 1000;\n\t\t\tthis.oldTime = newTime;\n\n\t\t\tthis.elapsedTime += diff;\n\n\t\t}\n\n\t\treturn diff;\n\n\t}\n\n};\n\n/**\n * @author bhouston / http://clara.io\n * @author WestLangley / http://github.com/WestLangley\n *\n * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system\n *\n * The poles (phi) are at the positive and negative y axis.\n * The equator starts at positive z.\n */\n\nfunction Spherical( radius, phi, theta ) {\n\n\tthis.radius = ( radius !== undefined ) ? radius : 1.0;\n\tthis.phi = ( phi !== undefined ) ? phi : 0; // up / down towards top and bottom pole\n\tthis.theta = ( theta !== undefined ) ? theta : 0; // around the equator of the sphere\n\n\treturn this;\n\n}\n\nSpherical.prototype = {\n\n\tconstructor: Spherical,\n\n\tset: function ( radius, phi, theta ) {\n\n\t\tthis.radius = radius;\n\t\tthis.phi = phi;\n\t\tthis.theta = theta;\n\n\t\treturn this;\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor().copy( this );\n\n\t},\n\n\tcopy: function ( other ) {\n\n\t\tthis.radius = other.radius;\n\t\tthis.phi = other.phi;\n\t\tthis.theta = other.theta;\n\n\t\treturn this;\n\n\t},\n\n\t// restrict phi to be betwee EPS and PI-EPS\n\tmakeSafe: function() {\n\n\t\tvar EPS = 0.000001;\n\t\tthis.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) );\n\n\t\treturn this;\n\n\t},\n\n\tsetFromVector3: function( vec3 ) {\n\n\t\tthis.radius = vec3.length();\n\n\t\tif ( this.radius === 0 ) {\n\n\t\t\tthis.theta = 0;\n\t\t\tthis.phi = 0;\n\n\t\t} else {\n\n\t\t\tthis.theta = Math.atan2( vec3.x, vec3.z ); // equator angle around y-up axis\n\t\t\tthis.phi = Math.acos( _Math.clamp( vec3.y / this.radius, - 1, 1 ) ); // polar angle\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n};\n\n/**\n * @author Mugen87 / https://github.com/Mugen87\n *\n * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system\n *\n */\n\nfunction Cylindrical( radius, theta, y ) {\n\n\tthis.radius = ( radius !== undefined ) ? radius : 1.0; // distance from the origin to a point in the x-z plane\n\tthis.theta = ( theta !== undefined ) ? theta : 0; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis\n\tthis.y = ( y !== undefined ) ? y : 0; // height above the x-z plane\n\n\treturn this;\n\n}\n\nCylindrical.prototype = {\n\n\tconstructor: Cylindrical,\n\n\tset: function ( radius, theta, y ) {\n\n\t\tthis.radius = radius;\n\t\tthis.theta = theta;\n\t\tthis.y = y;\n\n\t\treturn this;\n\n\t},\n\n\tclone: function () {\n\n\t\treturn new this.constructor().copy( this );\n\n\t},\n\n\tcopy: function ( other ) {\n\n\t\tthis.radius = other.radius;\n\t\tthis.theta = other.theta;\n\t\tthis.y = other.y;\n\n\t\treturn this;\n\n\t},\n\n\tsetFromVector3: function( vec3 ) {\n\n\t\tthis.radius = Math.sqrt( vec3.x * vec3.x + vec3.z * vec3.z );\n\t\tthis.theta = Math.atan2( vec3.x, vec3.z );\n\t\tthis.y = vec3.y;\n\n\t\treturn this;\n\n\t}\n\n};\n\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nfunction MorphBlendMesh( geometry, material ) {\n\r\n\tMesh.call( this, geometry, material );\r\n\r\n\tthis.animationsMap = {};\r\n\tthis.animationsList = [];\r\n\r\n\t// prepare default animation\r\n\t// (all frames played together in 1 second)\r\n\r\n\tvar numFrames = this.geometry.morphTargets.length;\r\n\r\n\tvar name = \"__default\";\r\n\r\n\tvar startFrame = 0;\r\n\tvar endFrame = numFrames - 1;\r\n\r\n\tvar fps = numFrames / 1;\r\n\r\n\tthis.createAnimation( name, startFrame, endFrame, fps );\r\n\tthis.setAnimationWeight( name, 1 );\r\n\r\n}\r\n\r\nMorphBlendMesh.prototype = Object.create( Mesh.prototype );\r\nMorphBlendMesh.prototype.constructor = MorphBlendMesh;\r\n\r\nMorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) {\r\n\r\n\tvar animation = {\r\n\r\n\t\tstart: start,\r\n\t\tend: end,\r\n\r\n\t\tlength: end - start + 1,\r\n\r\n\t\tfps: fps,\r\n\t\tduration: ( end - start ) / fps,\r\n\r\n\t\tlastFrame: 0,\r\n\t\tcurrentFrame: 0,\r\n\r\n\t\tactive: false,\r\n\r\n\t\ttime: 0,\r\n\t\tdirection: 1,\r\n\t\tweight: 1,\r\n\r\n\t\tdirectionBackwards: false,\r\n\t\tmirroredLoop: false\r\n\r\n\t};\r\n\r\n\tthis.animationsMap[ name ] = animation;\r\n\tthis.animationsList.push( animation );\r\n\r\n};\r\n\r\nMorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) {\r\n\r\n\tvar pattern = /([a-z]+)_?(\\d+)/i;\r\n\r\n\tvar firstAnimation, frameRanges = {};\r\n\r\n\tvar geometry = this.geometry;\r\n\r\n\tfor ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) {\r\n\r\n\t\tvar morph = geometry.morphTargets[ i ];\r\n\t\tvar chunks = morph.name.match( pattern );\r\n\r\n\t\tif ( chunks && chunks.length > 1 ) {\r\n\r\n\t\t\tvar name = chunks[ 1 ];\r\n\r\n\t\t\tif ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: - Infinity };\r\n\r\n\t\t\tvar range = frameRanges[ name ];\r\n\r\n\t\t\tif ( i < range.start ) range.start = i;\r\n\t\t\tif ( i > range.end ) range.end = i;\r\n\r\n\t\t\tif ( ! firstAnimation ) firstAnimation = name;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfor ( var name in frameRanges ) {\r\n\r\n\t\tvar range = frameRanges[ name ];\r\n\t\tthis.createAnimation( name, range.start, range.end, fps );\r\n\r\n\t}\r\n\r\n\tthis.firstAnimation = firstAnimation;\r\n\r\n};\r\n\r\nMorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) {\r\n\r\n\tvar animation = this.animationsMap[ name ];\r\n\r\n\tif ( animation ) {\r\n\r\n\t\tanimation.direction = 1;\r\n\t\tanimation.directionBackwards = false;\r\n\r\n\t}\r\n\r\n};\r\n\r\nMorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) {\r\n\r\n\tvar animation = this.animationsMap[ name ];\r\n\r\n\tif ( animation ) {\r\n\r\n\t\tanimation.direction = - 1;\r\n\t\tanimation.directionBackwards = true;\r\n\r\n\t}\r\n\r\n};\r\n\r\nMorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) {\r\n\r\n\tvar animation = this.animationsMap[ name ];\r\n\r\n\tif ( animation ) {\r\n\r\n\t\tanimation.fps = fps;\r\n\t\tanimation.duration = ( animation.end - animation.start ) / animation.fps;\r\n\r\n\t}\r\n\r\n};\r\n\r\nMorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) {\r\n\r\n\tvar animation = this.animationsMap[ name ];\r\n\r\n\tif ( animation ) {\r\n\r\n\t\tanimation.duration = duration;\r\n\t\tanimation.fps = ( animation.end - animation.start ) / animation.duration;\r\n\r\n\t}\r\n\r\n};\r\n\r\nMorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) {\r\n\r\n\tvar animation = this.animationsMap[ name ];\r\n\r\n\tif ( animation ) {\r\n\r\n\t\tanimation.weight = weight;\r\n\r\n\t}\r\n\r\n};\r\n\r\nMorphBlendMesh.prototype.setAnimationTime = function ( name, time ) {\r\n\r\n\tvar animation = this.animationsMap[ name ];\r\n\r\n\tif ( animation ) {\r\n\r\n\t\tanimation.time = time;\r\n\r\n\t}\r\n\r\n};\r\n\r\nMorphBlendMesh.prototype.getAnimationTime = function ( name ) {\r\n\r\n\tvar time = 0;\r\n\r\n\tvar animation = this.animationsMap[ name ];\r\n\r\n\tif ( animation ) {\r\n\r\n\t\ttime = animation.time;\r\n\r\n\t}\r\n\r\n\treturn time;\r\n\r\n};\r\n\r\nMorphBlendMesh.prototype.getAnimationDuration = function ( name ) {\r\n\r\n\tvar duration = - 1;\r\n\r\n\tvar animation = this.animationsMap[ name ];\r\n\r\n\tif ( animation ) {\r\n\r\n\t\tduration = animation.duration;\r\n\r\n\t}\r\n\r\n\treturn duration;\r\n\r\n};\r\n\r\nMorphBlendMesh.prototype.playAnimation = function ( name ) {\r\n\r\n\tvar animation = this.animationsMap[ name ];\r\n\r\n\tif ( animation ) {\r\n\r\n\t\tanimation.time = 0;\r\n\t\tanimation.active = true;\r\n\r\n\t} else {\r\n\r\n\t\tconsole.warn( \"THREE.MorphBlendMesh: animation[\" + name + \"] undefined in .playAnimation()\" );\r\n\r\n\t}\r\n\r\n};\r\n\r\nMorphBlendMesh.prototype.stopAnimation = function ( name ) {\r\n\r\n\tvar animation = this.animationsMap[ name ];\r\n\r\n\tif ( animation ) {\r\n\r\n\t\tanimation.active = false;\r\n\r\n\t}\r\n\r\n};\r\n\r\nMorphBlendMesh.prototype.update = function ( delta ) {\r\n\r\n\tfor ( var i = 0, il = this.animationsList.length; i < il; i ++ ) {\r\n\r\n\t\tvar animation = this.animationsList[ i ];\r\n\r\n\t\tif ( ! animation.active ) continue;\r\n\r\n\t\tvar frameTime = animation.duration / animation.length;\r\n\r\n\t\tanimation.time += animation.direction * delta;\r\n\r\n\t\tif ( animation.mirroredLoop ) {\r\n\r\n\t\t\tif ( animation.time > animation.duration || animation.time < 0 ) {\r\n\r\n\t\t\t\tanimation.direction *= - 1;\r\n\r\n\t\t\t\tif ( animation.time > animation.duration ) {\r\n\r\n\t\t\t\t\tanimation.time = animation.duration;\r\n\t\t\t\t\tanimation.directionBackwards = true;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( animation.time < 0 ) {\r\n\r\n\t\t\t\t\tanimation.time = 0;\r\n\t\t\t\t\tanimation.directionBackwards = false;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\r\n\t\t\tanimation.time = animation.time % animation.duration;\r\n\r\n\t\t\tif ( animation.time < 0 ) animation.time += animation.duration;\r\n\r\n\t\t}\r\n\r\n\t\tvar keyframe = animation.start + _Math.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 );\r\n\t\tvar weight = animation.weight;\r\n\r\n\t\tif ( keyframe !== animation.currentFrame ) {\r\n\r\n\t\t\tthis.morphTargetInfluences[ animation.lastFrame ] = 0;\r\n\t\t\tthis.morphTargetInfluences[ animation.currentFrame ] = 1 * weight;\r\n\r\n\t\t\tthis.morphTargetInfluences[ keyframe ] = 0;\r\n\r\n\t\t\tanimation.lastFrame = animation.currentFrame;\r\n\t\t\tanimation.currentFrame = keyframe;\r\n\r\n\t\t}\r\n\r\n\t\tvar mix = ( animation.time % frameTime ) / frameTime;\r\n\r\n\t\tif ( animation.directionBackwards ) mix = 1 - mix;\r\n\r\n\t\tif ( animation.currentFrame !== animation.lastFrame ) {\r\n\r\n\t\t\tthis.morphTargetInfluences[ animation.currentFrame ] = mix * weight;\r\n\t\t\tthis.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tthis.morphTargetInfluences[ animation.currentFrame ] = weight;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n};\n\n/**\n * @author alteredq / http://alteredqualia.com/\n */\n\nfunction ImmediateRenderObject( material ) {\n\n\tObject3D.call( this );\n\n\tthis.material = material;\n\tthis.render = function ( renderCallback ) {};\n\n}\n\nImmediateRenderObject.prototype = Object.create( Object3D.prototype );\nImmediateRenderObject.prototype.constructor = ImmediateRenderObject;\n\nImmediateRenderObject.prototype.isImmediateRenderObject = true;\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author WestLangley / http://github.com/WestLangley\n*/\n\nfunction VertexNormalsHelper( object, size, hex, linewidth ) {\n\n\tthis.object = object;\n\n\tthis.size = ( size !== undefined ) ? size : 1;\n\n\tvar color = ( hex !== undefined ) ? hex : 0xff0000;\n\n\tvar width = ( linewidth !== undefined ) ? linewidth : 1;\n\n\t//\n\n\tvar nNormals = 0;\n\n\tvar objGeometry = this.object.geometry;\n\n\tif ( objGeometry && objGeometry.isGeometry ) {\n\n\t\tnNormals = objGeometry.faces.length * 3;\n\n\t} else if ( objGeometry && objGeometry.isBufferGeometry ) {\n\n\t\tnNormals = objGeometry.attributes.normal.count;\n\n\t}\n\n\t//\n\n\tvar geometry = new BufferGeometry();\n\n\tvar positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 );\n\n\tgeometry.addAttribute( 'position', positions );\n\n\tLineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) );\n\n\t//\n\n\tthis.matrixAutoUpdate = false;\n\n\tthis.update();\n\n}\n\nVertexNormalsHelper.prototype = Object.create( LineSegments.prototype );\nVertexNormalsHelper.prototype.constructor = VertexNormalsHelper;\n\nVertexNormalsHelper.prototype.update = ( function () {\n\n\tvar v1 = new Vector3();\n\tvar v2 = new Vector3();\n\tvar normalMatrix = new Matrix3();\n\n\treturn function update() {\n\n\t\tvar keys = [ 'a', 'b', 'c' ];\n\n\t\tthis.object.updateMatrixWorld( true );\n\n\t\tnormalMatrix.getNormalMatrix( this.object.matrixWorld );\n\n\t\tvar matrixWorld = this.object.matrixWorld;\n\n\t\tvar position = this.geometry.attributes.position;\n\n\t\t//\n\n\t\tvar objGeometry = this.object.geometry;\n\n\t\tif ( objGeometry && objGeometry.isGeometry ) {\n\n\t\t\tvar vertices = objGeometry.vertices;\n\n\t\t\tvar faces = objGeometry.faces;\n\n\t\t\tvar idx = 0;\n\n\t\t\tfor ( var i = 0, l = faces.length; i < l; i ++ ) {\n\n\t\t\t\tvar face = faces[ i ];\n\n\t\t\t\tfor ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {\n\n\t\t\t\t\tvar vertex = vertices[ face[ keys[ j ] ] ];\n\n\t\t\t\t\tvar normal = face.vertexNormals[ j ];\n\n\t\t\t\t\tv1.copy( vertex ).applyMatrix4( matrixWorld );\n\n\t\t\t\t\tv2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );\n\n\t\t\t\t\tposition.setXYZ( idx, v1.x, v1.y, v1.z );\n\n\t\t\t\t\tidx = idx + 1;\n\n\t\t\t\t\tposition.setXYZ( idx, v2.x, v2.y, v2.z );\n\n\t\t\t\t\tidx = idx + 1;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else if ( objGeometry && objGeometry.isBufferGeometry ) {\n\n\t\t\tvar objPos = objGeometry.attributes.position;\n\n\t\t\tvar objNorm = objGeometry.attributes.normal;\n\n\t\t\tvar idx = 0;\n\n\t\t\t// for simplicity, ignore index and drawcalls, and render every normal\n\n\t\t\tfor ( var j = 0, jl = objPos.count; j < jl; j ++ ) {\n\n\t\t\t\tv1.set( objPos.getX( j ), objPos.getY( j ), objPos.getZ( j ) ).applyMatrix4( matrixWorld );\n\n\t\t\t\tv2.set( objNorm.getX( j ), objNorm.getY( j ), objNorm.getZ( j ) );\n\n\t\t\t\tv2.applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );\n\n\t\t\t\tposition.setXYZ( idx, v1.x, v1.y, v1.z );\n\n\t\t\t\tidx = idx + 1;\n\n\t\t\t\tposition.setXYZ( idx, v2.x, v2.y, v2.z );\n\n\t\t\t\tidx = idx + 1;\n\n\t\t\t}\n\n\t\t}\n\n\t\tposition.needsUpdate = true;\n\n\t\treturn this;\n\n\t};\n\n}() );\n\n/**\n * @author alteredq / http://alteredqualia.com/\n * @author mrdoob / http://mrdoob.com/\n * @author WestLangley / http://github.com/WestLangley\n*/\n\nfunction SpotLightHelper( light ) {\n\n\tObject3D.call( this );\n\n\tthis.light = light;\n\tthis.light.updateMatrixWorld();\n\n\tthis.matrix = light.matrixWorld;\n\tthis.matrixAutoUpdate = false;\n\n\tvar geometry = new BufferGeometry();\n\n\tvar positions = [\n\t\t0, 0, 0, 0, 0, 1,\n\t\t0, 0, 0, 1, 0, 1,\n\t\t0, 0, 0, - 1, 0, 1,\n\t\t0, 0, 0, 0, 1, 1,\n\t\t0, 0, 0, 0, - 1, 1\n\t];\n\n\tfor ( var i = 0, j = 1, l = 32; i < l; i ++, j ++ ) {\n\n\t\tvar p1 = ( i / l ) * Math.PI * 2;\n\t\tvar p2 = ( j / l ) * Math.PI * 2;\n\n\t\tpositions.push(\n\t\t\tMath.cos( p1 ), Math.sin( p1 ), 1,\n\t\t\tMath.cos( p2 ), Math.sin( p2 ), 1\n\t\t);\n\n\t}\n\n\tgeometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );\n\n\tvar material = new LineBasicMaterial( { fog: false } );\n\n\tthis.cone = new LineSegments( geometry, material );\n\tthis.add( this.cone );\n\n\tthis.update();\n\n}\n\nSpotLightHelper.prototype = Object.create( Object3D.prototype );\nSpotLightHelper.prototype.constructor = SpotLightHelper;\n\nSpotLightHelper.prototype.dispose = function () {\n\n\tthis.cone.geometry.dispose();\n\tthis.cone.material.dispose();\n\n};\n\nSpotLightHelper.prototype.update = function () {\n\n\tvar vector = new Vector3();\n\tvar vector2 = new Vector3();\n\n\treturn function update() {\n\n\t\tvar coneLength = this.light.distance ? this.light.distance : 1000;\n\t\tvar coneWidth = coneLength * Math.tan( this.light.angle );\n\n\t\tthis.cone.scale.set( coneWidth, coneWidth, coneLength );\n\n\t\tvector.setFromMatrixPosition( this.light.matrixWorld );\n\t\tvector2.setFromMatrixPosition( this.light.target.matrixWorld );\n\n\t\tthis.cone.lookAt( vector2.sub( vector ) );\n\n\t\tthis.cone.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );\n\n\t};\n\n}();\n\n/**\n * @author Sean Griffin / http://twitter.com/sgrif\n * @author Michael Guerrero / http://realitymeltdown.com\n * @author mrdoob / http://mrdoob.com/\n * @author ikerr / http://verold.com\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction SkeletonHelper( object ) {\n\n\tthis.bones = this.getBoneList( object );\n\n\tvar geometry = new BufferGeometry();\n\n\tvar vertices = [];\n\tvar colors = [];\n\n\tvar color1 = new Color( 0, 0, 1 );\n\tvar color2 = new Color( 0, 1, 0 );\n\n\tfor ( var i = 0; i < this.bones.length; i ++ ) {\n\n\t\tvar bone = this.bones[ i ];\n\n\t\tif ( bone.parent && bone.parent.isBone ) {\n\n\t\t\tvertices.push( 0, 0, 0 );\n\t\t\tvertices.push( 0, 0, 0 );\n\t\t\tcolors.push( color1.r, color1.g, color1.b );\n\t\t\tcolors.push( color2.r, color2.g, color2.b );\n\n\t\t}\n\n\t}\n\n\tgeometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\tgeometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\tvar material = new LineBasicMaterial( { vertexColors: VertexColors, depthTest: false, depthWrite: false, transparent: true } );\n\n\tLineSegments.call( this, geometry, material );\n\n\tthis.root = object;\n\n\tthis.matrix = object.matrixWorld;\n\tthis.matrixAutoUpdate = false;\n\n\tthis.update();\n\n}\n\n\nSkeletonHelper.prototype = Object.create( LineSegments.prototype );\nSkeletonHelper.prototype.constructor = SkeletonHelper;\n\nSkeletonHelper.prototype.getBoneList = function( object ) {\n\n\tvar boneList = [];\n\n\tif ( object && object.isBone ) {\n\n\t\tboneList.push( object );\n\n\t}\n\n\tfor ( var i = 0; i < object.children.length; i ++ ) {\n\n\t\tboneList.push.apply( boneList, this.getBoneList( object.children[ i ] ) );\n\n\t}\n\n\treturn boneList;\n\n};\n\nSkeletonHelper.prototype.update = function () {\n\n\tvar vector = new Vector3();\n\n\tvar boneMatrix = new Matrix4();\n\tvar matrixWorldInv = new Matrix4();\n\n\treturn function update() {\n\n\t\tvar geometry = this.geometry;\n\t\tvar position = geometry.getAttribute( 'position' );\n\n\t\tmatrixWorldInv.getInverse( this.root.matrixWorld );\n\n\t\tfor ( var i = 0, j = 0; i < this.bones.length; i ++ ) {\n\n\t\t\tvar bone = this.bones[ i ];\n\n\t\t\tif ( bone.parent && bone.parent.isBone ) {\n\n\t\t\t\tboneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld );\n\t\t\t\tvector.setFromMatrixPosition( boneMatrix );\n\t\t\t\tposition.setXYZ( j, vector.x, vector.y, vector.z );\n\n\t\t\t\tboneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld );\n\t\t\t\tvector.setFromMatrixPosition( boneMatrix );\n\t\t\t\tposition.setXYZ( j + 1, vector.x, vector.y, vector.z );\n\n\t\t\t\tj += 2;\n\n\t\t\t}\n\n\t\t}\n\n\t\tgeometry.getAttribute( 'position' ).needsUpdate = true;\n\n\t};\n\n}();\n\n/**\n * @author alteredq / http://alteredqualia.com/\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction PointLightHelper( light, sphereSize ) {\n\n\tthis.light = light;\n\tthis.light.updateMatrixWorld();\n\n\tvar geometry = new SphereBufferGeometry( sphereSize, 4, 2 );\n\tvar material = new MeshBasicMaterial( { wireframe: true, fog: false } );\n\tmaterial.color.copy( this.light.color ).multiplyScalar( this.light.intensity );\n\n\tMesh.call( this, geometry, material );\n\n\tthis.matrix = this.light.matrixWorld;\n\tthis.matrixAutoUpdate = false;\n\n\t/*\n\tvar distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 );\n\tvar distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } );\n\n\tthis.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial );\n\tthis.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial );\n\n\tvar d = light.distance;\n\n\tif ( d === 0.0 ) {\n\n\t\tthis.lightDistance.visible = false;\n\n\t} else {\n\n\t\tthis.lightDistance.scale.set( d, d, d );\n\n\t}\n\n\tthis.add( this.lightDistance );\n\t*/\n\n}\n\nPointLightHelper.prototype = Object.create( Mesh.prototype );\nPointLightHelper.prototype.constructor = PointLightHelper;\n\nPointLightHelper.prototype.dispose = function () {\n\n\tthis.geometry.dispose();\n\tthis.material.dispose();\n\n};\n\nPointLightHelper.prototype.update = function () {\n\n\tthis.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );\n\n\t/*\n\tvar d = this.light.distance;\n\n\tif ( d === 0.0 ) {\n\n\t\tthis.lightDistance.visible = false;\n\n\t} else {\n\n\t\tthis.lightDistance.visible = true;\n\t\tthis.lightDistance.scale.set( d, d, d );\n\n\t}\n\t*/\n\n};\n\n/**\n * @author abelnation / http://github.com/abelnation\n * @author Mugen87 / http://github.com/Mugen87\n */\n\nfunction RectAreaLightHelper( light ) {\n\n\tObject3D.call( this );\n\n\tthis.light = light;\n\tthis.light.updateMatrixWorld();\n\n\tvar materialFront = new MeshBasicMaterial( {\n\t\tcolor: light.color,\n\t\tfog: false\n\t} );\n\n\tvar materialBack = new MeshBasicMaterial( {\n\t\tcolor: light.color,\n\t\tfog: false,\n\t\twireframe: true\n\t} );\n\n\tvar geometry = new BufferGeometry();\n\n\tgeometry.addAttribute( 'position', new BufferAttribute( new Float32Array( 6 * 3 ), 3 ) );\n\n\t// shows the \"front\" of the light, e.g. where light comes from\n\n\tthis.add( new Mesh( geometry, materialFront ) );\n\n\t// shows the \"back\" of the light, which does not emit light\n\n\tthis.add( new Mesh( geometry, materialBack ) );\n\n\tthis.update();\n\n}\n\nRectAreaLightHelper.prototype = Object.create( Object3D.prototype );\nRectAreaLightHelper.prototype.constructor = RectAreaLightHelper;\n\nRectAreaLightHelper.prototype.dispose = function () {\n\n\tthis.children[ 0 ].geometry.dispose();\n\tthis.children[ 0 ].material.dispose();\n\tthis.children[ 1 ].geometry.dispose();\n\tthis.children[ 1 ].material.dispose();\n\n};\n\nRectAreaLightHelper.prototype.update = function () {\n\n\tvar vector1 = new Vector3();\n\tvar vector2 = new Vector3();\n\n\treturn function update() {\n\n\t\tvar mesh1 = this.children[ 0 ];\n\t\tvar mesh2 = this.children[ 1 ];\n\n\t\tif ( this.light.target ) {\n\n\t\t\tvector1.setFromMatrixPosition( this.light.matrixWorld );\n\t\t\tvector2.setFromMatrixPosition( this.light.target.matrixWorld );\n\n\t\t\tvar lookVec = vector2.clone().sub( vector1 );\n\t\t\tmesh1.lookAt( lookVec );\n\t\t\tmesh2.lookAt( lookVec );\n\n\t\t}\n\n\t\t// update materials\n\n\t\tmesh1.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );\n\t\tmesh2.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );\n\n\t\t// calculate new dimensions of the helper\n\n\t\tvar hx = this.light.width * 0.5;\n\t\tvar hy = this.light.height * 0.5;\n\n\t\t// because the buffer attribute is shared over both geometries, we only have to update once\n\n\t\tvar position = mesh1.geometry.getAttribute( 'position' );\n\t\tvar array = position.array;\n\n\t\t// first face\n\n\t\tarray[ 0 ] = hx; array[ 1 ] = - hy; array[ 2 ] = 0;\n\t\tarray[ 3 ] = hx; array[ 4 ] = hy; array[ 5 ] = 0;\n\t\tarray[ 6 ] = - hx; array[ 7 ] = hy; array[ 8 ] = 0;\n\n\t\t// second face\n\n\t\tarray[ 9 ] = - hx; array[ 10 ] = hy; array[ 11 ] = 0;\n\t\tarray[ 12 ] = - hx; array[ 13 ] = - hy; array[ 14 ] = 0;\n\t\tarray[ 15 ] = hx; array[ 16 ] = - hy; array[ 17 ] = 0;\n\n\t\tposition.needsUpdate = true;\n\n\t};\n\n}();\n\n/**\n * @author alteredq / http://alteredqualia.com/\n * @author mrdoob / http://mrdoob.com/\n * @author Mugen87 / https://github.com/Mugen87\n */\n\nfunction HemisphereLightHelper( light, size ) {\n\n\tObject3D.call( this );\n\n\tthis.light = light;\n\tthis.light.updateMatrixWorld();\n\n\tthis.matrix = light.matrixWorld;\n\tthis.matrixAutoUpdate = false;\n\n\tvar geometry = new OctahedronBufferGeometry( size );\n\tgeometry.rotateY( Math.PI * 0.5 );\n\n\tvar material = new MeshBasicMaterial( { vertexColors: VertexColors, wireframe: true } );\n\n\tvar position = geometry.getAttribute( 'position' );\n\tvar colors = new Float32Array( position.count * 3 );\n\n\tgeometry.addAttribute( 'color', new BufferAttribute( colors, 3 ) );\n\n\tthis.add( new Mesh( geometry, material ) );\n\n\tthis.update();\n\n}\n\nHemisphereLightHelper.prototype = Object.create( Object3D.prototype );\nHemisphereLightHelper.prototype.constructor = HemisphereLightHelper;\n\nHemisphereLightHelper.prototype.dispose = function () {\n\n\tthis.children[ 0 ].geometry.dispose();\n\tthis.children[ 0 ].material.dispose();\n\n};\n\nHemisphereLightHelper.prototype.update = function () {\n\n\tvar vector = new Vector3();\n\n\tvar color1 = new Color();\n\tvar color2 = new Color();\n\n\treturn function update() {\n\n\t\tvar mesh = this.children[ 0 ];\n\n\t\tvar colors = mesh.geometry.getAttribute( 'color' );\n\n\t\tcolor1.copy( this.light.color ).multiplyScalar( this.light.intensity );\n\t\tcolor2.copy( this.light.groundColor ).multiplyScalar( this.light.intensity );\n\n\t\tfor ( var i = 0, l = colors.count; i < l; i ++ ) {\n\n\t\t\tvar color = ( i < ( l / 2 ) ) ? color1 : color2;\n\n\t\t\tcolors.setXYZ( i, color.r, color.g, color.b );\n\n\t\t}\n\n\t\tmesh.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() );\n\n\t\tcolors.needsUpdate = true;\n\n\t};\n\n}();\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction GridHelper( size, divisions, color1, color2 ) {\n\n\tsize = size || 10;\n\tdivisions = divisions || 10;\n\tcolor1 = new Color( color1 !== undefined ? color1 : 0x444444 );\n\tcolor2 = new Color( color2 !== undefined ? color2 : 0x888888 );\n\n\tvar center = divisions / 2;\n\tvar step = size / divisions;\n\tvar halfSize = size / 2;\n\n\tvar vertices = [], colors = [];\n\n\tfor ( var i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) {\n\n\t\tvertices.push( - halfSize, 0, k, halfSize, 0, k );\n\t\tvertices.push( k, 0, - halfSize, k, 0, halfSize );\n\n\t\tvar color = i === center ? color1 : color2;\n\n\t\tcolor.toArray( colors, j ); j += 3;\n\t\tcolor.toArray( colors, j ); j += 3;\n\t\tcolor.toArray( colors, j ); j += 3;\n\t\tcolor.toArray( colors, j ); j += 3;\n\n\t}\n\n\tvar geometry = new BufferGeometry();\n\tgeometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\tgeometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\tvar material = new LineBasicMaterial( { vertexColors: VertexColors } );\n\n\tLineSegments.call( this, geometry, material );\n\n}\n\nGridHelper.prototype = Object.create( LineSegments.prototype );\nGridHelper.prototype.constructor = GridHelper;\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author Mugen87 / http://github.com/Mugen87\n * @author Hectate / http://www.github.com/Hectate\n */\n\nfunction PolarGridHelper( radius, radials, circles, divisions, color1, color2 ) {\n\n\tradius = radius || 10;\n\tradials = radials || 16;\n\tcircles = circles || 8;\n\tdivisions = divisions || 64;\n\tcolor1 = new Color( color1 !== undefined ? color1 : 0x444444 );\n\tcolor2 = new Color( color2 !== undefined ? color2 : 0x888888 );\n\n\tvar vertices = [];\n\tvar colors = [];\n\n\tvar x, z;\n\tvar v, i, j, r, color;\n\n\t// create the radials\n\n\tfor ( i = 0; i <= radials; i ++ ) {\n\n\t\tv = ( i / radials ) * ( Math.PI * 2 );\n\n\t\tx = Math.sin( v ) * radius;\n\t\tz = Math.cos( v ) * radius;\n\n\t\tvertices.push( 0, 0, 0 );\n\t\tvertices.push( x, 0, z );\n\n\t\tcolor = ( i & 1 ) ? color1 : color2;\n\n\t\tcolors.push( color.r, color.g, color.b );\n\t\tcolors.push( color.r, color.g, color.b );\n\n\t}\n\n\t// create the circles\n\n\tfor ( i = 0; i <= circles; i ++ ) {\n\n\t\tcolor = ( i & 1 ) ? color1 : color2;\n\n\t\tr = radius - ( radius / circles * i );\n\n\t\tfor ( j = 0; j < divisions; j ++ ) {\n\n\t\t\t// first vertex\n\n\t\t\tv = ( j / divisions ) * ( Math.PI * 2 );\n\n\t\t\tx = Math.sin( v ) * r;\n\t\t\tz = Math.cos( v ) * r;\n\n\t\t\tvertices.push( x, 0, z );\n\t\t\tcolors.push( color.r, color.g, color.b );\n\n\t\t\t// second vertex\n\n\t\t\tv = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 );\n\n\t\t\tx = Math.sin( v ) * r;\n\t\t\tz = Math.cos( v ) * r;\n\n\t\t\tvertices.push( x, 0, z );\n\t\t\tcolors.push( color.r, color.g, color.b );\n\n\t\t}\n\n\t}\n\n\tvar geometry = new BufferGeometry();\n\tgeometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\tgeometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\tvar material = new LineBasicMaterial( { vertexColors: VertexColors } );\n\n\tLineSegments.call( this, geometry, material );\n\n}\n\nPolarGridHelper.prototype = Object.create( LineSegments.prototype );\nPolarGridHelper.prototype.constructor = PolarGridHelper;\n\n/**\n * @author mrdoob / http://mrdoob.com/\n * @author WestLangley / http://github.com/WestLangley\n*/\n\nfunction FaceNormalsHelper( object, size, hex, linewidth ) {\n\n\t// FaceNormalsHelper only supports THREE.Geometry\n\n\tthis.object = object;\n\n\tthis.size = ( size !== undefined ) ? size : 1;\n\n\tvar color = ( hex !== undefined ) ? hex : 0xffff00;\n\n\tvar width = ( linewidth !== undefined ) ? linewidth : 1;\n\n\t//\n\n\tvar nNormals = 0;\n\n\tvar objGeometry = this.object.geometry;\n\n\tif ( objGeometry && objGeometry.isGeometry ) {\n\n\t\tnNormals = objGeometry.faces.length;\n\n\t} else {\n\n\t\tconsole.warn( 'THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead.' );\n\n\t}\n\n\t//\n\n\tvar geometry = new BufferGeometry();\n\n\tvar positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 );\n\n\tgeometry.addAttribute( 'position', positions );\n\n\tLineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) );\n\n\t//\n\n\tthis.matrixAutoUpdate = false;\n\tthis.update();\n\n}\n\nFaceNormalsHelper.prototype = Object.create( LineSegments.prototype );\nFaceNormalsHelper.prototype.constructor = FaceNormalsHelper;\n\nFaceNormalsHelper.prototype.update = ( function () {\n\n\tvar v1 = new Vector3();\n\tvar v2 = new Vector3();\n\tvar normalMatrix = new Matrix3();\n\n\treturn function update() {\n\n\t\tthis.object.updateMatrixWorld( true );\n\n\t\tnormalMatrix.getNormalMatrix( this.object.matrixWorld );\n\n\t\tvar matrixWorld = this.object.matrixWorld;\n\n\t\tvar position = this.geometry.attributes.position;\n\n\t\t//\n\n\t\tvar objGeometry = this.object.geometry;\n\n\t\tvar vertices = objGeometry.vertices;\n\n\t\tvar faces = objGeometry.faces;\n\n\t\tvar idx = 0;\n\n\t\tfor ( var i = 0, l = faces.length; i < l; i ++ ) {\n\n\t\t\tvar face = faces[ i ];\n\n\t\t\tvar normal = face.normal;\n\n\t\t\tv1.copy( vertices[ face.a ] )\n\t\t\t\t.add( vertices[ face.b ] )\n\t\t\t\t.add( vertices[ face.c ] )\n\t\t\t\t.divideScalar( 3 )\n\t\t\t\t.applyMatrix4( matrixWorld );\n\n\t\t\tv2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );\n\n\t\t\tposition.setXYZ( idx, v1.x, v1.y, v1.z );\n\n\t\t\tidx = idx + 1;\n\n\t\t\tposition.setXYZ( idx, v2.x, v2.y, v2.z );\n\n\t\t\tidx = idx + 1;\n\n\t\t}\n\n\t\tposition.needsUpdate = true;\n\n\t\treturn this;\n\n\t};\n\n}() );\n\n/**\n * @author alteredq / http://alteredqualia.com/\n * @author mrdoob / http://mrdoob.com/\n * @author WestLangley / http://github.com/WestLangley\n */\n\nfunction DirectionalLightHelper( light, size ) {\n\n\tObject3D.call( this );\n\n\tthis.light = light;\n\tthis.light.updateMatrixWorld();\n\n\tthis.matrix = light.matrixWorld;\n\tthis.matrixAutoUpdate = false;\n\n\tif ( size === undefined ) size = 1;\n\n\tvar geometry = new BufferGeometry();\n\tgeometry.addAttribute( 'position', new Float32BufferAttribute( [\n\t\t- size, size, 0,\n\t\t size, size, 0,\n\t\t size, - size, 0,\n\t\t- size, - size, 0,\n\t\t- size, size, 0\n\t], 3 ) );\n\n\tvar material = new LineBasicMaterial( { fog: false } );\n\n\tthis.add( new Line( geometry, material ) );\n\n\tgeometry = new BufferGeometry();\n\tgeometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );\n\n\tthis.add( new Line( geometry, material ));\n\n\tthis.update();\n\n}\n\nDirectionalLightHelper.prototype = Object.create( Object3D.prototype );\nDirectionalLightHelper.prototype.constructor = DirectionalLightHelper;\n\nDirectionalLightHelper.prototype.dispose = function () {\n\n\tvar lightPlane = this.children[ 0 ];\n\tvar targetLine = this.children[ 1 ];\n\n\tlightPlane.geometry.dispose();\n\tlightPlane.material.dispose();\n\ttargetLine.geometry.dispose();\n\ttargetLine.material.dispose();\n\n};\n\nDirectionalLightHelper.prototype.update = function () {\n\n\tvar v1 = new Vector3();\n\tvar v2 = new Vector3();\n\tvar v3 = new Vector3();\n\n\treturn function update() {\n\n\t\tv1.setFromMatrixPosition( this.light.matrixWorld );\n\t\tv2.setFromMatrixPosition( this.light.target.matrixWorld );\n\t\tv3.subVectors( v2, v1 );\n\n\t\tvar lightPlane = this.children[ 0 ];\n\t\tvar targetLine = this.children[ 1 ];\n\n\t\tlightPlane.lookAt( v3 );\n\t\tlightPlane.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );\n\n\t\ttargetLine.lookAt( v3 );\n\t\ttargetLine.scale.z = v3.length();\n\n\t};\n\n}();\n\n/**\n * @author alteredq / http://alteredqualia.com/\n * @author Mugen87 / https://github.com/Mugen87\n *\n *\t- shows frustum, line of sight and up of the camera\n *\t- suitable for fast updates\n * \t- based on frustum visualization in lightgl.js shadowmap example\n *\t\thttp://evanw.github.com/lightgl.js/tests/shadowmap.html\n */\n\nfunction CameraHelper( camera ) {\n\n\tvar geometry = new BufferGeometry();\n\tvar material = new LineBasicMaterial( { color: 0xffffff, vertexColors: FaceColors } );\n\n\tvar vertices = [];\n\tvar colors = [];\n\n\tvar pointMap = {};\n\n\t// colors\n\n\tvar colorFrustum = new Color( 0xffaa00 );\n\tvar colorCone = new Color( 0xff0000 );\n\tvar colorUp = new Color( 0x00aaff );\n\tvar colorTarget = new Color( 0xffffff );\n\tvar colorCross = new Color( 0x333333 );\n\n\t// near\n\n\taddLine( \"n1\", \"n2\", colorFrustum );\n\taddLine( \"n2\", \"n4\", colorFrustum );\n\taddLine( \"n4\", \"n3\", colorFrustum );\n\taddLine( \"n3\", \"n1\", colorFrustum );\n\n\t// far\n\n\taddLine( \"f1\", \"f2\", colorFrustum );\n\taddLine( \"f2\", \"f4\", colorFrustum );\n\taddLine( \"f4\", \"f3\", colorFrustum );\n\taddLine( \"f3\", \"f1\", colorFrustum );\n\n\t// sides\n\n\taddLine( \"n1\", \"f1\", colorFrustum );\n\taddLine( \"n2\", \"f2\", colorFrustum );\n\taddLine( \"n3\", \"f3\", colorFrustum );\n\taddLine( \"n4\", \"f4\", colorFrustum );\n\n\t// cone\n\n\taddLine( \"p\", \"n1\", colorCone );\n\taddLine( \"p\", \"n2\", colorCone );\n\taddLine( \"p\", \"n3\", colorCone );\n\taddLine( \"p\", \"n4\", colorCone );\n\n\t// up\n\n\taddLine( \"u1\", \"u2\", colorUp );\n\taddLine( \"u2\", \"u3\", colorUp );\n\taddLine( \"u3\", \"u1\", colorUp );\n\n\t// target\n\n\taddLine( \"c\", \"t\", colorTarget );\n\taddLine( \"p\", \"c\", colorCross );\n\n\t// cross\n\n\taddLine( \"cn1\", \"cn2\", colorCross );\n\taddLine( \"cn3\", \"cn4\", colorCross );\n\n\taddLine( \"cf1\", \"cf2\", colorCross );\n\taddLine( \"cf3\", \"cf4\", colorCross );\n\n\tfunction addLine( a, b, color ) {\n\n\t\taddPoint( a, color );\n\t\taddPoint( b, color );\n\n\t}\n\n\tfunction addPoint( id, color ) {\n\n\t\tvertices.push( 0, 0, 0 );\n\t\tcolors.push( color.r, color.g, color.b );\n\n\t\tif ( pointMap[ id ] === undefined ) {\n\n\t\t\tpointMap[ id ] = [];\n\n\t\t}\n\n\t\tpointMap[ id ].push( ( vertices.length / 3 ) - 1 );\n\n\t}\n\n\tgeometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\tgeometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\tLineSegments.call( this, geometry, material );\n\n\tthis.camera = camera;\n\tif ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix();\n\n\tthis.matrix = camera.matrixWorld;\n\tthis.matrixAutoUpdate = false;\n\n\tthis.pointMap = pointMap;\n\n\tthis.update();\n\n}\n\nCameraHelper.prototype = Object.create( LineSegments.prototype );\nCameraHelper.prototype.constructor = CameraHelper;\n\nCameraHelper.prototype.update = function () {\n\n\tvar geometry, pointMap;\n\n\tvar vector = new Vector3();\n\tvar camera = new Camera();\n\n\tfunction setPoint( point, x, y, z ) {\n\n\t\tvector.set( x, y, z ).unproject( camera );\n\n\t\tvar points = pointMap[ point ];\n\n\t\tif ( points !== undefined ) {\n\n\t\t\tvar position = geometry.getAttribute( 'position' );\n\n\t\t\tfor ( var i = 0, l = points.length; i < l; i ++ ) {\n\n\t\t\t\tposition.setXYZ( points[ i ], vector.x, vector.y, vector.z );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\treturn function update() {\n\n\t\tgeometry = this.geometry;\n\t\tpointMap = this.pointMap;\n\n\t\tvar w = 1, h = 1;\n\n\t\t// we need just camera projection matrix\n\t\t// world matrix must be identity\n\n\t\tcamera.projectionMatrix.copy( this.camera.projectionMatrix );\n\n\t\t// center / target\n\n\t\tsetPoint( \"c\", 0, 0, - 1 );\n\t\tsetPoint( \"t\", 0, 0, 1 );\n\n\t\t// near\n\n\t\tsetPoint( \"n1\", - w, - h, - 1 );\n\t\tsetPoint( \"n2\", w, - h, - 1 );\n\t\tsetPoint( \"n3\", - w, h, - 1 );\n\t\tsetPoint( \"n4\", w, h, - 1 );\n\n\t\t// far\n\n\t\tsetPoint( \"f1\", - w, - h, 1 );\n\t\tsetPoint( \"f2\", w, - h, 1 );\n\t\tsetPoint( \"f3\", - w, h, 1 );\n\t\tsetPoint( \"f4\", w, h, 1 );\n\n\t\t// up\n\n\t\tsetPoint( \"u1\", w * 0.7, h * 1.1, - 1 );\n\t\tsetPoint( \"u2\", - w * 0.7, h * 1.1, - 1 );\n\t\tsetPoint( \"u3\", 0, h * 2, - 1 );\n\n\t\t// cross\n\n\t\tsetPoint( \"cf1\", - w, 0, 1 );\n\t\tsetPoint( \"cf2\", w, 0, 1 );\n\t\tsetPoint( \"cf3\", 0, - h, 1 );\n\t\tsetPoint( \"cf4\", 0, h, 1 );\n\n\t\tsetPoint( \"cn1\", - w, 0, - 1 );\n\t\tsetPoint( \"cn2\", w, 0, - 1 );\n\t\tsetPoint( \"cn3\", 0, - h, - 1 );\n\t\tsetPoint( \"cn4\", 0, h, - 1 );\n\n\t\tgeometry.getAttribute( 'position' ).needsUpdate = true;\n\n\t};\n\n}();\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction BoxHelper( object, color ) {\n\n\tif ( color === undefined ) color = 0xffff00;\n\n\tvar indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );\n\tvar positions = new Float32Array( 8 * 3 );\n\n\tvar geometry = new BufferGeometry();\n\tgeometry.setIndex( new BufferAttribute( indices, 1 ) );\n\tgeometry.addAttribute( 'position', new BufferAttribute( positions, 3 ) );\n\n\tLineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) );\n\n\tif ( object !== undefined ) {\n\n\t\tthis.update( object );\n\n\t}\n\n}\n\nBoxHelper.prototype = Object.create( LineSegments.prototype );\nBoxHelper.prototype.constructor = BoxHelper;\n\nBoxHelper.prototype.update = ( function () {\n\n\tvar box = new Box3();\n\n\treturn function update( object ) {\n\n\t\tif ( object && object.isBox3 ) {\n\n\t\t\tbox.copy( object );\n\n\t\t} else {\n\n\t\t\tbox.setFromObject( object );\n\n\t\t}\n\n\t\tif ( box.isEmpty() ) return;\n\n\t\tvar min = box.min;\n\t\tvar max = box.max;\n\n\t\t/*\n\t\t 5____4\n\t\t1/___0/|\n\t\t| 6__|_7\n\t\t2/___3/\n\n\t\t0: max.x, max.y, max.z\n\t\t1: min.x, max.y, max.z\n\t\t2: min.x, min.y, max.z\n\t\t3: max.x, min.y, max.z\n\t\t4: max.x, max.y, min.z\n\t\t5: min.x, max.y, min.z\n\t\t6: min.x, min.y, min.z\n\t\t7: max.x, min.y, min.z\n\t\t*/\n\n\t\tvar position = this.geometry.attributes.position;\n\t\tvar array = position.array;\n\n\t\tarray[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z;\n\t\tarray[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z;\n\t\tarray[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z;\n\t\tarray[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z;\n\t\tarray[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z;\n\t\tarray[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z;\n\t\tarray[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z;\n\t\tarray[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z;\n\n\t\tposition.needsUpdate = true;\n\n\t\tthis.geometry.computeBoundingSphere();\n\n\t};\n\n} )();\n\n/**\n * @author WestLangley / http://github.com/WestLangley\n * @author zz85 / http://github.com/zz85\n * @author bhouston / http://clara.io\n *\n * Creates an arrow for visualizing directions\n *\n * Parameters:\n * dir - Vector3\n * origin - Vector3\n * length - Number\n * color - color in hex value\n * headLength - Number\n * headWidth - Number\n */\n\nvar lineGeometry;\nvar coneGeometry;\n\nfunction ArrowHelper( dir, origin, length, color, headLength, headWidth ) {\n\n\t// dir is assumed to be normalized\n\n\tObject3D.call( this );\n\n\tif ( color === undefined ) color = 0xffff00;\n\tif ( length === undefined ) length = 1;\n\tif ( headLength === undefined ) headLength = 0.2 * length;\n\tif ( headWidth === undefined ) headWidth = 0.2 * headLength;\n\n\tif ( lineGeometry === undefined ) {\n\n\t\tlineGeometry = new BufferGeometry();\n\t\tlineGeometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );\n\n\t\tconeGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 );\n\t\tconeGeometry.translate( 0, - 0.5, 0 );\n\n\t}\n\n\tthis.position.copy( origin );\n\n\tthis.line = new Line( lineGeometry, new LineBasicMaterial( { color: color } ) );\n\tthis.line.matrixAutoUpdate = false;\n\tthis.add( this.line );\n\n\tthis.cone = new Mesh( coneGeometry, new MeshBasicMaterial( { color: color } ) );\n\tthis.cone.matrixAutoUpdate = false;\n\tthis.add( this.cone );\n\n\tthis.setDirection( dir );\n\tthis.setLength( length, headLength, headWidth );\n\n}\n\nArrowHelper.prototype = Object.create( Object3D.prototype );\nArrowHelper.prototype.constructor = ArrowHelper;\n\nArrowHelper.prototype.setDirection = ( function () {\n\n\tvar axis = new Vector3();\n\tvar radians;\n\n\treturn function setDirection( dir ) {\n\n\t\t// dir is assumed to be normalized\n\n\t\tif ( dir.y > 0.99999 ) {\n\n\t\t\tthis.quaternion.set( 0, 0, 0, 1 );\n\n\t\t} else if ( dir.y < - 0.99999 ) {\n\n\t\t\tthis.quaternion.set( 1, 0, 0, 0 );\n\n\t\t} else {\n\n\t\t\taxis.set( dir.z, 0, - dir.x ).normalize();\n\n\t\t\tradians = Math.acos( dir.y );\n\n\t\t\tthis.quaternion.setFromAxisAngle( axis, radians );\n\n\t\t}\n\n\t};\n\n}() );\n\nArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) {\n\n\tif ( headLength === undefined ) headLength = 0.2 * length;\n\tif ( headWidth === undefined ) headWidth = 0.2 * headLength;\n\n\tthis.line.scale.set( 1, Math.max( 0, length - headLength ), 1 );\n\tthis.line.updateMatrix();\n\n\tthis.cone.scale.set( headWidth, headLength, headWidth );\n\tthis.cone.position.y = length;\n\tthis.cone.updateMatrix();\n\n};\n\nArrowHelper.prototype.setColor = function ( color ) {\n\n\tthis.line.material.color.copy( color );\n\tthis.cone.material.color.copy( color );\n\n};\n\n/**\n * @author sroucheray / http://sroucheray.org/\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction AxisHelper( size ) {\n\n\tsize = size || 1;\n\n\tvar vertices = [\n\t\t0, 0, 0, size, 0, 0,\n\t\t0, 0, 0, 0, size, 0,\n\t\t0, 0, 0, 0, 0, size\n\t];\n\n\tvar colors = [\n\t\t1, 0, 0, 1, 0.6, 0,\n\t\t0, 1, 0, 0.6, 1, 0,\n\t\t0, 0, 1, 0, 0.6, 1\n\t];\n\n\tvar geometry = new BufferGeometry();\n\tgeometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\tgeometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\tvar material = new LineBasicMaterial( { vertexColors: VertexColors } );\n\n\tLineSegments.call( this, geometry, material );\n\n}\n\nAxisHelper.prototype = Object.create( LineSegments.prototype );\nAxisHelper.prototype.constructor = AxisHelper;\n\n/**\n * @author zz85 https://github.com/zz85\n *\n * Centripetal CatmullRom Curve - which is useful for avoiding\n * cusps and self-intersections in non-uniform catmull rom curves.\n * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf\n *\n * curve.type accepts centripetal(default), chordal and catmullrom\n * curve.tension is used for catmullrom which defaults to 0.5\n */\n\n\n/*\nBased on an optimized c++ solution in\n - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/\n - http://ideone.com/NoEbVM\n\nThis CubicPoly class could be used for reusing some variables and calculations,\nbut for three.js curve use, it could be possible inlined and flatten into a single function call\nwhich can be placed in CurveUtils.\n*/\n\nfunction CubicPoly() {\n\n\tvar c0 = 0, c1 = 0, c2 = 0, c3 = 0;\n\n\t/*\n\t * Compute coefficients for a cubic polynomial\n\t * p(s) = c0 + c1*s + c2*s^2 + c3*s^3\n\t * such that\n\t * p(0) = x0, p(1) = x1\n\t * and\n\t * p'(0) = t0, p'(1) = t1.\n\t */\n\tfunction init( x0, x1, t0, t1 ) {\n\n\t\tc0 = x0;\n\t\tc1 = t0;\n\t\tc2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;\n\t\tc3 = 2 * x0 - 2 * x1 + t0 + t1;\n\n\t}\n\n\treturn {\n\n\t\tinitCatmullRom: function ( x0, x1, x2, x3, tension ) {\n\n\t\t\tinit( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );\n\n\t\t},\n\n\t\tinitNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {\n\n\t\t\t// compute tangents when parameterized in [t1,t2]\n\t\t\tvar t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;\n\t\t\tvar t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;\n\n\t\t\t// rescale tangents for parametrization in [0,1]\n\t\t\tt1 *= dt1;\n\t\t\tt2 *= dt1;\n\n\t\t\tinit( x1, x2, t1, t2 );\n\n\t\t},\n\n\t\tcalc: function ( t ) {\n\n\t\t\tvar t2 = t * t;\n\t\t\tvar t3 = t2 * t;\n\t\t\treturn c0 + c1 * t + c2 * t2 + c3 * t3;\n\n\t\t}\n\n\t};\n\n}\n\n//\n\nvar tmp = new Vector3();\nvar px = new CubicPoly();\nvar py = new CubicPoly();\nvar pz = new CubicPoly();\n\nfunction CatmullRomCurve3( p /* array of Vector3 */ ) {\n\n\tthis.points = p || [];\n\tthis.closed = false;\n\n}\n\nCatmullRomCurve3.prototype = Object.create( Curve.prototype );\nCatmullRomCurve3.prototype.constructor = CatmullRomCurve3;\n\nCatmullRomCurve3.prototype.getPoint = function ( t ) {\n\n\tvar points = this.points;\n\tvar l = points.length;\n\n\tif ( l < 2 ) console.log( 'duh, you need at least 2 points' );\n\n\tvar point = ( l - ( this.closed ? 0 : 1 ) ) * t;\n\tvar intPoint = Math.floor( point );\n\tvar weight = point - intPoint;\n\n\tif ( this.closed ) {\n\n\t\tintPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length;\n\n\t} else if ( weight === 0 && intPoint === l - 1 ) {\n\n\t\tintPoint = l - 2;\n\t\tweight = 1;\n\n\t}\n\n\tvar p0, p1, p2, p3; // 4 points\n\n\tif ( this.closed || intPoint > 0 ) {\n\n\t\tp0 = points[ ( intPoint - 1 ) % l ];\n\n\t} else {\n\n\t\t// extrapolate first point\n\t\ttmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );\n\t\tp0 = tmp;\n\n\t}\n\n\tp1 = points[ intPoint % l ];\n\tp2 = points[ ( intPoint + 1 ) % l ];\n\n\tif ( this.closed || intPoint + 2 < l ) {\n\n\t\tp3 = points[ ( intPoint + 2 ) % l ];\n\n\t} else {\n\n\t\t// extrapolate last point\n\t\ttmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );\n\t\tp3 = tmp;\n\n\t}\n\n\tif ( this.type === undefined || this.type === 'centripetal' || this.type === 'chordal' ) {\n\n\t\t// init Centripetal / Chordal Catmull-Rom\n\t\tvar pow = this.type === 'chordal' ? 0.5 : 0.25;\n\t\tvar dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );\n\t\tvar dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );\n\t\tvar dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );\n\n\t\t// safety check for repeated points\n\t\tif ( dt1 < 1e-4 ) dt1 = 1.0;\n\t\tif ( dt0 < 1e-4 ) dt0 = dt1;\n\t\tif ( dt2 < 1e-4 ) dt2 = dt1;\n\n\t\tpx.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );\n\t\tpy.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );\n\t\tpz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );\n\n\t} else if ( this.type === 'catmullrom' ) {\n\n\t\tvar tension = this.tension !== undefined ? this.tension : 0.5;\n\t\tpx.initCatmullRom( p0.x, p1.x, p2.x, p3.x, tension );\n\t\tpy.initCatmullRom( p0.y, p1.y, p2.y, p3.y, tension );\n\t\tpz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, tension );\n\n\t}\n\n\treturn new Vector3( px.calc( weight ), py.calc( weight ), pz.calc( weight ) );\n\n};\n\nfunction CubicBezierCurve3( v0, v1, v2, v3 ) {\n\n\tthis.v0 = v0;\n\tthis.v1 = v1;\n\tthis.v2 = v2;\n\tthis.v3 = v3;\n\n}\n\nCubicBezierCurve3.prototype = Object.create( Curve.prototype );\nCubicBezierCurve3.prototype.constructor = CubicBezierCurve3;\n\nCubicBezierCurve3.prototype.getPoint = function ( t ) {\n\n\tvar v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;\n\n\treturn new Vector3(\n\t\tCubicBezier( t, v0.x, v1.x, v2.x, v3.x ),\n\t\tCubicBezier( t, v0.y, v1.y, v2.y, v3.y ),\n\t\tCubicBezier( t, v0.z, v1.z, v2.z, v3.z )\n\t);\n\n};\n\nfunction QuadraticBezierCurve3( v0, v1, v2 ) {\n\n\tthis.v0 = v0;\n\tthis.v1 = v1;\n\tthis.v2 = v2;\n\n}\n\nQuadraticBezierCurve3.prototype = Object.create( Curve.prototype );\nQuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3;\n\nQuadraticBezierCurve3.prototype.getPoint = function ( t ) {\n\n\tvar v0 = this.v0, v1 = this.v1, v2 = this.v2;\n\n\treturn new Vector3(\n\t\tQuadraticBezier( t, v0.x, v1.x, v2.x ),\n\t\tQuadraticBezier( t, v0.y, v1.y, v2.y ),\n\t\tQuadraticBezier( t, v0.z, v1.z, v2.z )\n\t);\n\n};\n\nfunction LineCurve3( v1, v2 ) {\n\n\tthis.v1 = v1;\n\tthis.v2 = v2;\n\n}\n\nLineCurve3.prototype = Object.create( Curve.prototype );\nLineCurve3.prototype.constructor = LineCurve3;\n\nLineCurve3.prototype.getPoint = function ( t ) {\n\n\tif ( t === 1 ) {\n\n\t\treturn this.v2.clone();\n\n\t}\n\n\tvar vector = new Vector3();\n\n\tvector.subVectors( this.v2, this.v1 ); // diff\n\tvector.multiplyScalar( t );\n\tvector.add( this.v1 );\n\n\treturn vector;\n\n};\n\nfunction ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {\n\n\tEllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );\n\n}\n\nArcCurve.prototype = Object.create( EllipseCurve.prototype );\nArcCurve.prototype.constructor = ArcCurve;\n\n/**\n * @author alteredq / http://alteredqualia.com/\n */\n\nvar SceneUtils = {\n\n\tcreateMultiMaterialObject: function ( geometry, materials ) {\n\n\t\tvar group = new Group();\n\n\t\tfor ( var i = 0, l = materials.length; i < l; i ++ ) {\n\n\t\t\tgroup.add( new Mesh( geometry, materials[ i ] ) );\n\n\t\t}\n\n\t\treturn group;\n\n\t},\n\n\tdetach: function ( child, parent, scene ) {\n\n\t\tchild.applyMatrix( parent.matrixWorld );\n\t\tparent.remove( child );\n\t\tscene.add( child );\n\n\t},\n\n\tattach: function ( child, scene, parent ) {\n\n\t\tvar matrixWorldInverse = new Matrix4();\n\t\tmatrixWorldInverse.getInverse( parent.matrixWorld );\n\t\tchild.applyMatrix( matrixWorldInverse );\n\n\t\tscene.remove( child );\n\t\tparent.add( child );\n\n\t}\n\n};\n\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nfunction Face4( a, b, c, d, normal, color, materialIndex ) {\n\n\tconsole.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' );\n\treturn new Face3( a, b, c, normal, color, materialIndex );\n\n}\n\nvar LineStrip = 0;\n\nvar LinePieces = 1;\n\nfunction MeshFaceMaterial( materials ) {\n\n\tconsole.warn( 'THREE.MeshFaceMaterial has been renamed to THREE.MultiMaterial.' );\n\treturn new MultiMaterial( materials );\n\n}\n\nfunction PointCloud( geometry, material ) {\n\n\tconsole.warn( 'THREE.PointCloud has been renamed to THREE.Points.' );\n\treturn new Points( geometry, material );\n\n}\n\nfunction Particle( material ) {\n\n\tconsole.warn( 'THREE.Particle has been renamed to THREE.Sprite.' );\n\treturn new Sprite( material );\n\n}\n\nfunction ParticleSystem( geometry, material ) {\n\n\tconsole.warn( 'THREE.ParticleSystem has been renamed to THREE.Points.' );\n\treturn new Points( geometry, material );\n\n}\n\nfunction PointCloudMaterial( parameters ) {\n\n\tconsole.warn( 'THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.' );\n\treturn new PointsMaterial( parameters );\n\n}\n\nfunction ParticleBasicMaterial( parameters ) {\n\n\tconsole.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.' );\n\treturn new PointsMaterial( parameters );\n\n}\n\nfunction ParticleSystemMaterial( parameters ) {\n\n\tconsole.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.' );\n\treturn new PointsMaterial( parameters );\n\n}\n\nfunction Vertex( x, y, z ) {\n\n\tconsole.warn( 'THREE.Vertex has been removed. Use THREE.Vector3 instead.' );\n\treturn new Vector3( x, y, z );\n\n}\n\n//\n\nfunction DynamicBufferAttribute( array, itemSize ) {\n\n\tconsole.warn( 'THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setDynamic( true ) instead.' );\n\treturn new BufferAttribute( array, itemSize ).setDynamic( true );\n\n}\n\nfunction Int8Attribute( array, itemSize ) {\n\n\tconsole.warn( 'THREE.Int8Attribute has been removed. Use new THREE.Int8BufferAttribute() instead.' );\n\treturn new Int8BufferAttribute( array, itemSize );\n\n}\n\nfunction Uint8Attribute( array, itemSize ) {\n\n\tconsole.warn( 'THREE.Uint8Attribute has been removed. Use new THREE.Uint8BufferAttribute() instead.' );\n\treturn new Uint8BufferAttribute( array, itemSize );\n\n}\n\nfunction Uint8ClampedAttribute( array, itemSize ) {\n\n\tconsole.warn( 'THREE.Uint8ClampedAttribute has been removed. Use new THREE.Uint8ClampedBufferAttribute() instead.' );\n\treturn new Uint8ClampedBufferAttribute( array, itemSize );\n\n}\n\nfunction Int16Attribute( array, itemSize ) {\n\n\tconsole.warn( 'THREE.Int16Attribute has been removed. Use new THREE.Int16BufferAttribute() instead.' );\n\treturn new Int16BufferAttribute( array, itemSize );\n\n}\n\nfunction Uint16Attribute( array, itemSize ) {\n\n\tconsole.warn( 'THREE.Uint16Attribute has been removed. Use new THREE.Uint16BufferAttribute() instead.' );\n\treturn new Uint16BufferAttribute( array, itemSize );\n\n}\n\nfunction Int32Attribute( array, itemSize ) {\n\n\tconsole.warn( 'THREE.Int32Attribute has been removed. Use new THREE.Int32BufferAttribute() instead.' );\n\treturn new Int32BufferAttribute( array, itemSize );\n\n}\n\nfunction Uint32Attribute( array, itemSize ) {\n\n\tconsole.warn( 'THREE.Uint32Attribute has been removed. Use new THREE.Uint32BufferAttribute() instead.' );\n\treturn new Uint32BufferAttribute( array, itemSize );\n\n}\n\nfunction Float32Attribute( array, itemSize ) {\n\n\tconsole.warn( 'THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead.' );\n\treturn new Float32BufferAttribute( array, itemSize );\n\n}\n\nfunction Float64Attribute( array, itemSize ) {\n\n\tconsole.warn( 'THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead.' );\n\treturn new Float64BufferAttribute( array, itemSize );\n\n}\n\n//\n\nCurve.create = function ( construct, getPoint ) {\n\n\tconsole.log( 'THREE.Curve.create() has been deprecated' );\n\n\tconstruct.prototype = Object.create( Curve.prototype );\n\tconstruct.prototype.constructor = construct;\n\tconstruct.prototype.getPoint = getPoint;\n\n\treturn construct;\n\n};\n\n//\n\nfunction ClosedSplineCurve3( points ) {\n\n\tconsole.warn( 'THREE.ClosedSplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' );\n\n\tCatmullRomCurve3.call( this, points );\n\tthis.type = 'catmullrom';\n\tthis.closed = true;\n\n}\n\nClosedSplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype );\n\n//\n\nfunction SplineCurve3( points ) {\n\n\tconsole.warn( 'THREE.SplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' );\n\n\tCatmullRomCurve3.call( this, points );\n\tthis.type = 'catmullrom';\n\n}\n\nSplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype );\n\n//\n\nfunction Spline( points ) {\n\n\tconsole.warn( 'THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.' );\n\n\tCatmullRomCurve3.call( this, points );\n\tthis.type = 'catmullrom';\n\n}\n\nSpline.prototype = Object.create( CatmullRomCurve3.prototype );\n\nObject.assign( Spline.prototype, {\n\n\tinitFromArray: function ( a ) {\n\n\t\tconsole.error( 'THREE.Spline: .initFromArray() has been removed.' );\n\n\t},\n\tgetControlPointsArray: function ( optionalTarget ) {\n\n\t\tconsole.error( 'THREE.Spline: .getControlPointsArray() has been removed.' );\n\n\t},\n\treparametrizeByArcLength: function ( samplingCoef ) {\n\n\t\tconsole.error( 'THREE.Spline: .reparametrizeByArcLength() has been removed.' );\n\n\t}\n\n} );\n\n//\nfunction BoundingBoxHelper( object, color ) {\n\n\tconsole.warn( 'THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead.' );\n\treturn new BoxHelper( object, color );\n\n}\n\nfunction EdgesHelper( object, hex ) {\n\n\tconsole.warn( 'THREE.EdgesHelper has been removed. Use THREE.EdgesGeometry instead.' );\n\treturn new LineSegments( new EdgesGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) );\n\n}\n\nGridHelper.prototype.setColors = function () {\n\n\tconsole.error( 'THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.' );\n\n};\n\nfunction WireframeHelper( object, hex ) {\n\n\tconsole.warn( 'THREE.WireframeHelper has been removed. Use THREE.WireframeGeometry instead.' );\n\treturn new LineSegments( new WireframeGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) );\n\n}\n\n//\n\nfunction XHRLoader( manager ) {\n\n\tconsole.warn( 'THREE.XHRLoader has been renamed to THREE.FileLoader.' );\n\treturn new FileLoader( manager );\n\n}\n\nfunction BinaryTextureLoader( manager ) {\n\n\tconsole.warn( 'THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader.' );\n\treturn new DataTextureLoader( manager );\n\n}\n\n//\n\nObject.assign( Box2.prototype, {\n\n\tcenter: function ( optionalTarget ) {\n\n\t\tconsole.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' );\n\t\treturn this.getCenter( optionalTarget );\n\n\t},\n\tempty: function () {\n\n\t\tconsole.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' );\n\t\treturn this.isEmpty();\n\n\t},\n\tisIntersectionBox: function ( box ) {\n\n\t\tconsole.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' );\n\t\treturn this.intersectsBox( box );\n\n\t},\n\tsize: function ( optionalTarget ) {\n\n\t\tconsole.warn( 'THREE.Box2: .size() has been renamed to .getSize().' );\n\t\treturn this.getSize( optionalTarget );\n\n\t}\n} );\n\nObject.assign( Box3.prototype, {\n\n\tcenter: function ( optionalTarget ) {\n\n\t\tconsole.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' );\n\t\treturn this.getCenter( optionalTarget );\n\n\t},\n\tempty: function () {\n\n\t\tconsole.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' );\n\t\treturn this.isEmpty();\n\n\t},\n\tisIntersectionBox: function ( box ) {\n\n\t\tconsole.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' );\n\t\treturn this.intersectsBox( box );\n\n\t},\n\tisIntersectionSphere: function ( sphere ) {\n\n\t\tconsole.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' );\n\t\treturn this.intersectsSphere( sphere );\n\n\t},\n\tsize: function ( optionalTarget ) {\n\n\t\tconsole.warn( 'THREE.Box3: .size() has been renamed to .getSize().' );\n\t\treturn this.getSize( optionalTarget );\n\n\t}\n} );\n\nLine3.prototype.center = function ( optionalTarget ) {\n\n\tconsole.warn( 'THREE.Line3: .center() has been renamed to .getCenter().' );\n\treturn this.getCenter( optionalTarget );\n\n};\n\n_Math.random16 = function () {\n\n\tconsole.warn( 'THREE.Math.random16() has been deprecated. Use Math.random() instead.' );\n\treturn Math.random();\n\n};\n\nObject.assign( Matrix3.prototype, {\n\n\tflattenToArrayOffset: function ( array, offset ) {\n\n\t\tconsole.warn( \"THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.\" );\n\t\treturn this.toArray( array, offset );\n\n\t},\n\tmultiplyVector3: function ( vector ) {\n\n\t\tconsole.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' );\n\t\treturn vector.applyMatrix3( this );\n\n\t},\n\tmultiplyVector3Array: function ( a ) {\n\n\t\tconsole.warn( 'THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' );\n\t\treturn this.applyToVector3Array( a );\n\n\t},\n\tapplyToBuffer: function( buffer, offset, length ) {\n\n\t\tconsole.warn( 'THREE.Matrix3: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' );\n\t\treturn this.applyToBufferAttribute( buffer );\n\n\t},\n\tapplyToVector3Array: function( array, offset, length ) {\n\n\t\tconsole.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' );\n\n\t}\n\n} );\n\nObject.assign( Matrix4.prototype, {\n\n\textractPosition: function ( m ) {\n\n\t\tconsole.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' );\n\t\treturn this.copyPosition( m );\n\n\t},\n\tflattenToArrayOffset: function ( array, offset ) {\n\n\t\tconsole.warn( \"THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.\" );\n\t\treturn this.toArray( array, offset );\n\n\t},\n\tgetPosition: function () {\n\n\t\tvar v1;\n\n\t\treturn function getPosition() {\n\n\t\t\tif ( v1 === undefined ) v1 = new Vector3();\n\t\t\tconsole.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' );\n\t\t\treturn v1.setFromMatrixColumn( this, 3 );\n\n\t\t};\n\n\t}(),\n\tsetRotationFromQuaternion: function ( q ) {\n\n\t\tconsole.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' );\n\t\treturn this.makeRotationFromQuaternion( q );\n\n\t},\n\tmultiplyVector3: function ( vector ) {\n\n\t\tconsole.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' );\n\t\treturn vector.applyMatrix4( this );\n\n\t},\n\tmultiplyVector4: function ( vector ) {\n\n\t\tconsole.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' );\n\t\treturn vector.applyMatrix4( this );\n\n\t},\n\tmultiplyVector3Array: function ( a ) {\n\n\t\tconsole.warn( 'THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' );\n\t\treturn this.applyToVector3Array( a );\n\n\t},\n\trotateAxis: function ( v ) {\n\n\t\tconsole.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' );\n\t\tv.transformDirection( this );\n\n\t},\n\tcrossVector: function ( vector ) {\n\n\t\tconsole.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' );\n\t\treturn vector.applyMatrix4( this );\n\n\t},\n\ttranslate: function () {\n\n\t\tconsole.error( 'THREE.Matrix4: .translate() has been removed.' );\n\n\t},\n\trotateX: function () {\n\n\t\tconsole.error( 'THREE.Matrix4: .rotateX() has been removed.' );\n\n\t},\n\trotateY: function () {\n\n\t\tconsole.error( 'THREE.Matrix4: .rotateY() has been removed.' );\n\n\t},\n\trotateZ: function () {\n\n\t\tconsole.error( 'THREE.Matrix4: .rotateZ() has been removed.' );\n\n\t},\n\trotateByAxis: function () {\n\n\t\tconsole.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' );\n\n\t},\n\tapplyToBuffer: function( buffer, offset, length ) {\n\n\t\tconsole.warn( 'THREE.Matrix4: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' );\n\t\treturn this.applyToBufferAttribute( buffer );\n\n\t},\n\tapplyToVector3Array: function( array, offset, length ) {\n\n\t\tconsole.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' );\n\n\t},\n\tmakeFrustum: function( left, right, bottom, top, near, far ) {\n\n\t\tconsole.warn( 'THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead.' );\n\t\treturn this.makePerspective( left, right, top, bottom, near, far );\n\n\t}\n\n} );\n\nPlane.prototype.isIntersectionLine = function ( line ) {\n\n\tconsole.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' );\n\treturn this.intersectsLine( line );\n\n};\n\nQuaternion.prototype.multiplyVector3 = function ( vector ) {\n\n\tconsole.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );\n\treturn vector.applyQuaternion( this );\n\n};\n\nObject.assign( Ray.prototype, {\n\n\tisIntersectionBox: function ( box ) {\n\n\t\tconsole.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' );\n\t\treturn this.intersectsBox( box );\n\n\t},\n\tisIntersectionPlane: function ( plane ) {\n\n\t\tconsole.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' );\n\t\treturn this.intersectsPlane( plane );\n\n\t},\n\tisIntersectionSphere: function ( sphere ) {\n\n\t\tconsole.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' );\n\t\treturn this.intersectsSphere( sphere );\n\n\t}\n\n} );\n\nObject.assign( Shape.prototype, {\n\n\textrude: function ( options ) {\n\n\t\tconsole.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' );\n\t\treturn new ExtrudeGeometry( this, options );\n\n\t},\n\tmakeGeometry: function ( options ) {\n\n\t\tconsole.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' );\n\t\treturn new ShapeGeometry( this, options );\n\n\t}\n\n} );\n\nObject.assign( Vector2.prototype, {\n\n\tfromAttribute: function ( attribute, index, offset ) {\n\n\t\tconsole.error( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' );\n\t\treturn this.fromBufferAttribute( attribute, index, offset );\n\n\t}\n\n} );\n\nObject.assign( Vector3.prototype, {\n\n\tsetEulerFromRotationMatrix: function () {\n\n\t\tconsole.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' );\n\n\t},\n\tsetEulerFromQuaternion: function () {\n\n\t\tconsole.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' );\n\n\t},\n\tgetPositionFromMatrix: function ( m ) {\n\n\t\tconsole.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' );\n\t\treturn this.setFromMatrixPosition( m );\n\n\t},\n\tgetScaleFromMatrix: function ( m ) {\n\n\t\tconsole.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' );\n\t\treturn this.setFromMatrixScale( m );\n\n\t},\n\tgetColumnFromMatrix: function ( index, matrix ) {\n\n\t\tconsole.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' );\n\t\treturn this.setFromMatrixColumn( matrix, index );\n\n\t},\n\tapplyProjection: function ( m ) {\n\n\t\tconsole.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' );\n\t\treturn this.applyMatrix4( m );\n\n\t},\n\tfromAttribute: function ( attribute, index, offset ) {\n\n\t\tconsole.error( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' );\n\t\treturn this.fromBufferAttribute( attribute, index, offset );\n\n\t}\n\n} );\n\nObject.assign( Vector4.prototype, {\n\n\tfromAttribute: function ( attribute, index, offset ) {\n\n\t\tconsole.error( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' );\n\t\treturn this.fromBufferAttribute( attribute, index, offset );\n\n\t}\n\n} );\n\n//\n\nGeometry.prototype.computeTangents = function () {\n\n\tconsole.warn( 'THREE.Geometry: .computeTangents() has been removed.' );\n\n};\n\nObject.assign( Object3D.prototype, {\n\n\tgetChildByName: function ( name ) {\n\n\t\tconsole.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' );\n\t\treturn this.getObjectByName( name );\n\n\t},\n\trenderDepth: function () {\n\n\t\tconsole.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' );\n\n\t},\n\ttranslate: function ( distance, axis ) {\n\n\t\tconsole.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' );\n\t\treturn this.translateOnAxis( axis, distance );\n\n\t}\n\n} );\n\nObject.defineProperties( Object3D.prototype, {\n\n\teulerOrder: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );\n\t\t\treturn this.rotation.order;\n\n\t\t},\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );\n\t\t\tthis.rotation.order = value;\n\n\t\t}\n\t},\n\tuseQuaternion: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );\n\n\t\t},\n\t\tset: function () {\n\n\t\t\tconsole.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );\n\n\t\t}\n\t}\n\n} );\n\nObject.defineProperties( LOD.prototype, {\n\n\tobjects: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.LOD: .objects has been renamed to .levels.' );\n\t\t\treturn this.levels;\n\n\t\t}\n\t}\n\n} );\n\n//\n\nPerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) {\n\n\tconsole.warn( \"THREE.PerspectiveCamera.setLens is deprecated. \" +\n\t\t\t\"Use .setFocalLength and .filmGauge for a photographic setup.\" );\n\n\tif ( filmGauge !== undefined ) this.filmGauge = filmGauge;\n\tthis.setFocalLength( focalLength );\n\n};\n\n//\n\nObject.defineProperties( Light.prototype, {\n\tonlyShadow: {\n\t\tset: function () {\n\n\t\t\tconsole.warn( 'THREE.Light: .onlyShadow has been removed.' );\n\n\t\t}\n\t},\n\tshadowCameraFov: {\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' );\n\t\t\tthis.shadow.camera.fov = value;\n\n\t\t}\n\t},\n\tshadowCameraLeft: {\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' );\n\t\t\tthis.shadow.camera.left = value;\n\n\t\t}\n\t},\n\tshadowCameraRight: {\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' );\n\t\t\tthis.shadow.camera.right = value;\n\n\t\t}\n\t},\n\tshadowCameraTop: {\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' );\n\t\t\tthis.shadow.camera.top = value;\n\n\t\t}\n\t},\n\tshadowCameraBottom: {\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' );\n\t\t\tthis.shadow.camera.bottom = value;\n\n\t\t}\n\t},\n\tshadowCameraNear: {\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' );\n\t\t\tthis.shadow.camera.near = value;\n\n\t\t}\n\t},\n\tshadowCameraFar: {\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' );\n\t\t\tthis.shadow.camera.far = value;\n\n\t\t}\n\t},\n\tshadowCameraVisible: {\n\t\tset: function () {\n\n\t\t\tconsole.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' );\n\n\t\t}\n\t},\n\tshadowBias: {\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' );\n\t\t\tthis.shadow.bias = value;\n\n\t\t}\n\t},\n\tshadowDarkness: {\n\t\tset: function () {\n\n\t\t\tconsole.warn( 'THREE.Light: .shadowDarkness has been removed.' );\n\n\t\t}\n\t},\n\tshadowMapWidth: {\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' );\n\t\t\tthis.shadow.mapSize.width = value;\n\n\t\t}\n\t},\n\tshadowMapHeight: {\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' );\n\t\t\tthis.shadow.mapSize.height = value;\n\n\t\t}\n\t}\n} );\n\n//\n\nObject.defineProperties( BufferAttribute.prototype, {\n\n\tlength: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' );\n\t\t\treturn this.array.length;\n\n\t\t}\n\t}\n\n} );\n\nObject.assign( BufferGeometry.prototype, {\n\n\taddIndex: function ( index ) {\n\n\t\tconsole.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' );\n\t\tthis.setIndex( index );\n\n\t},\n\taddDrawCall: function ( start, count, indexOffset ) {\n\n\t\tif ( indexOffset !== undefined ) {\n\n\t\t\tconsole.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' );\n\n\t\t}\n\t\tconsole.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' );\n\t\tthis.addGroup( start, count );\n\n\t},\n\tclearDrawCalls: function () {\n\n\t\tconsole.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' );\n\t\tthis.clearGroups();\n\n\t},\n\tcomputeTangents: function () {\n\n\t\tconsole.warn( 'THREE.BufferGeometry: .computeTangents() has been removed.' );\n\n\t},\n\tcomputeOffsets: function () {\n\n\t\tconsole.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' );\n\n\t}\n\n} );\n\nObject.defineProperties( BufferGeometry.prototype, {\n\n\tdrawcalls: {\n\t\tget: function () {\n\n\t\t\tconsole.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' );\n\t\t\treturn this.groups;\n\n\t\t}\n\t},\n\toffsets: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' );\n\t\t\treturn this.groups;\n\n\t\t}\n\t}\n\n} );\n\n//\n\nObject.defineProperties( Uniform.prototype, {\n\n\tdynamic: {\n\t\tset: function () {\n\n\t\t\tconsole.warn( 'THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.' );\n\n\t\t}\n\t},\n\tonUpdate: {\n\t\tvalue: function () {\n\n\t\t\tconsole.warn( 'THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.' );\n\t\t\treturn this;\n\n\t\t}\n\t}\n\n} );\n\n//\n\nObject.defineProperties( Material.prototype, {\n\n\twrapAround: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.' + this.type + ': .wrapAround has been removed.' );\n\n\t\t},\n\t\tset: function () {\n\n\t\t\tconsole.warn( 'THREE.' + this.type + ': .wrapAround has been removed.' );\n\n\t\t}\n\t},\n\twrapRGB: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.' + this.type + ': .wrapRGB has been removed.' );\n\t\t\treturn new Color();\n\n\t\t}\n\t}\n\n} );\n\nObject.defineProperties( MeshPhongMaterial.prototype, {\n\n\tmetal: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.' );\n\t\t\treturn false;\n\n\t\t},\n\t\tset: function () {\n\n\t\t\tconsole.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead' );\n\n\t\t}\n\t}\n\n} );\n\nObject.defineProperties( ShaderMaterial.prototype, {\n\n\tderivatives: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );\n\t\t\treturn this.extensions.derivatives;\n\n\t\t},\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );\n\t\t\tthis.extensions.derivatives = value;\n\n\t\t}\n\t}\n\n} );\n\n//\n\nObject.assign( WebGLRenderer.prototype, {\n\n\tsupportsFloatTextures: function () {\n\n\t\tconsole.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \\'OES_texture_float\\' ).' );\n\t\treturn this.extensions.get( 'OES_texture_float' );\n\n\t},\n\tsupportsHalfFloatTextures: function () {\n\n\t\tconsole.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \\'OES_texture_half_float\\' ).' );\n\t\treturn this.extensions.get( 'OES_texture_half_float' );\n\n\t},\n\tsupportsStandardDerivatives: function () {\n\n\t\tconsole.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \\'OES_standard_derivatives\\' ).' );\n\t\treturn this.extensions.get( 'OES_standard_derivatives' );\n\n\t},\n\tsupportsCompressedTextureS3TC: function () {\n\n\t\tconsole.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \\'WEBGL_compressed_texture_s3tc\\' ).' );\n\t\treturn this.extensions.get( 'WEBGL_compressed_texture_s3tc' );\n\n\t},\n\tsupportsCompressedTexturePVRTC: function () {\n\n\t\tconsole.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \\'WEBGL_compressed_texture_pvrtc\\' ).' );\n\t\treturn this.extensions.get( 'WEBGL_compressed_texture_pvrtc' );\n\n\t},\n\tsupportsBlendMinMax: function () {\n\n\t\tconsole.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \\'EXT_blend_minmax\\' ).' );\n\t\treturn this.extensions.get( 'EXT_blend_minmax' );\n\n\t},\n\tsupportsVertexTextures: function () {\n\n\t\tconsole.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' );\n\t\treturn this.capabilities.vertexTextures;\n\n\t},\n\tsupportsInstancedArrays: function () {\n\n\t\tconsole.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \\'ANGLE_instanced_arrays\\' ).' );\n\t\treturn this.extensions.get( 'ANGLE_instanced_arrays' );\n\n\t},\n\tenableScissorTest: function ( boolean ) {\n\n\t\tconsole.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' );\n\t\tthis.setScissorTest( boolean );\n\n\t},\n\tinitMaterial: function () {\n\n\t\tconsole.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' );\n\n\t},\n\taddPrePlugin: function () {\n\n\t\tconsole.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' );\n\n\t},\n\taddPostPlugin: function () {\n\n\t\tconsole.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' );\n\n\t},\n\tupdateShadowMap: function () {\n\n\t\tconsole.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' );\n\n\t}\n\n} );\n\nObject.defineProperties( WebGLRenderer.prototype, {\n\n\tshadowMapEnabled: {\n\t\tget: function () {\n\n\t\t\treturn this.shadowMap.enabled;\n\n\t\t},\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' );\n\t\t\tthis.shadowMap.enabled = value;\n\n\t\t}\n\t},\n\tshadowMapType: {\n\t\tget: function () {\n\n\t\t\treturn this.shadowMap.type;\n\n\t\t},\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' );\n\t\t\tthis.shadowMap.type = value;\n\n\t\t}\n\t},\n\tshadowMapCullFace: {\n\t\tget: function () {\n\n\t\t\treturn this.shadowMap.cullFace;\n\n\t\t},\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .shadowMapCullFace is now .shadowMap.cullFace.' );\n\t\t\tthis.shadowMap.cullFace = value;\n\n\t\t}\n\t}\n} );\n\nObject.defineProperties( WebGLShadowMap.prototype, {\n\n\tcullFace: {\n\t\tget: function () {\n\n\t\t\treturn this.renderReverseSided ? CullFaceFront : CullFaceBack;\n\n\t\t},\n\t\tset: function ( cullFace ) {\n\n\t\t\tvar value = ( cullFace !== CullFaceBack );\n\t\t\tconsole.warn( \"WebGLRenderer: .shadowMap.cullFace is deprecated. Set .shadowMap.renderReverseSided to \" + value + \".\" );\n\t\t\tthis.renderReverseSided = value;\n\n\t\t}\n\t}\n\n} );\n\n//\n\nObject.defineProperties( WebGLRenderTarget.prototype, {\n\n\twrapS: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );\n\t\t\treturn this.texture.wrapS;\n\n\t\t},\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );\n\t\t\tthis.texture.wrapS = value;\n\n\t\t}\n\t},\n\twrapT: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );\n\t\t\treturn this.texture.wrapT;\n\n\t\t},\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );\n\t\t\tthis.texture.wrapT = value;\n\n\t\t}\n\t},\n\tmagFilter: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );\n\t\t\treturn this.texture.magFilter;\n\n\t\t},\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );\n\t\t\tthis.texture.magFilter = value;\n\n\t\t}\n\t},\n\tminFilter: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );\n\t\t\treturn this.texture.minFilter;\n\n\t\t},\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );\n\t\t\tthis.texture.minFilter = value;\n\n\t\t}\n\t},\n\tanisotropy: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );\n\t\t\treturn this.texture.anisotropy;\n\n\t\t},\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );\n\t\t\tthis.texture.anisotropy = value;\n\n\t\t}\n\t},\n\toffset: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );\n\t\t\treturn this.texture.offset;\n\n\t\t},\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );\n\t\t\tthis.texture.offset = value;\n\n\t\t}\n\t},\n\trepeat: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );\n\t\t\treturn this.texture.repeat;\n\n\t\t},\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );\n\t\t\tthis.texture.repeat = value;\n\n\t\t}\n\t},\n\tformat: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );\n\t\t\treturn this.texture.format;\n\n\t\t},\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );\n\t\t\tthis.texture.format = value;\n\n\t\t}\n\t},\n\ttype: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );\n\t\t\treturn this.texture.type;\n\n\t\t},\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );\n\t\t\tthis.texture.type = value;\n\n\t\t}\n\t},\n\tgenerateMipmaps: {\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );\n\t\t\treturn this.texture.generateMipmaps;\n\n\t\t},\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );\n\t\t\tthis.texture.generateMipmaps = value;\n\n\t\t}\n\t}\n\n} );\n\n//\n\nAudio.prototype.load = function ( file ) {\n\n\tconsole.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' );\n\tvar scope = this;\n\tvar audioLoader = new AudioLoader();\n\taudioLoader.load( file, function ( buffer ) {\n\n\t\tscope.setBuffer( buffer );\n\n\t} );\n\treturn this;\n\n};\n\nAudioAnalyser.prototype.getData = function () {\n\n\tconsole.warn( 'THREE.AudioAnalyser: .getData() is now .getFrequencyData().' );\n\treturn this.getFrequencyData();\n\n};\n\n//\n\nvar GeometryUtils = {\n\n\tmerge: function ( geometry1, geometry2, materialIndexOffset ) {\n\n\t\tconsole.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' );\n\t\tvar matrix;\n\n\t\tif ( geometry2.isMesh ) {\n\n\t\t\tgeometry2.matrixAutoUpdate && geometry2.updateMatrix();\n\n\t\t\tmatrix = geometry2.matrix;\n\t\t\tgeometry2 = geometry2.geometry;\n\n\t\t}\n\n\t\tgeometry1.merge( geometry2, matrix, materialIndexOffset );\n\n\t},\n\n\tcenter: function ( geometry ) {\n\n\t\tconsole.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' );\n\t\treturn geometry.center();\n\n\t}\n\n};\n\nvar ImageUtils = {\n\n\tcrossOrigin: undefined,\n\n\tloadTexture: function ( url, mapping, onLoad, onError ) {\n\n\t\tconsole.warn( 'THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.' );\n\n\t\tvar loader = new TextureLoader();\n\t\tloader.setCrossOrigin( this.crossOrigin );\n\n\t\tvar texture = loader.load( url, onLoad, undefined, onError );\n\n\t\tif ( mapping ) texture.mapping = mapping;\n\n\t\treturn texture;\n\n\t},\n\n\tloadTextureCube: function ( urls, mapping, onLoad, onError ) {\n\n\t\tconsole.warn( 'THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.' );\n\n\t\tvar loader = new CubeTextureLoader();\n\t\tloader.setCrossOrigin( this.crossOrigin );\n\n\t\tvar texture = loader.load( urls, onLoad, undefined, onError );\n\n\t\tif ( mapping ) texture.mapping = mapping;\n\n\t\treturn texture;\n\n\t},\n\n\tloadCompressedTexture: function () {\n\n\t\tconsole.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' );\n\n\t},\n\n\tloadCompressedTextureCube: function () {\n\n\t\tconsole.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' );\n\n\t}\n\n};\n\n//\n\nfunction Projector() {\n\n\tconsole.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' );\n\n\tthis.projectVector = function ( vector, camera ) {\n\n\t\tconsole.warn( 'THREE.Projector: .projectVector() is now vector.project().' );\n\t\tvector.project( camera );\n\n\t};\n\n\tthis.unprojectVector = function ( vector, camera ) {\n\n\t\tconsole.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' );\n\t\tvector.unproject( camera );\n\n\t};\n\n\tthis.pickingRay = function () {\n\n\t\tconsole.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );\n\n\t};\n\n}\n\n//\n\nfunction CanvasRenderer() {\n\n\tconsole.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' );\n\n\tthis.domElement = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );\n\tthis.clear = function () {};\n\tthis.render = function () {};\n\tthis.setClearColor = function () {};\n\tthis.setSize = function () {};\n\n}\n\nexport { WebGLRenderTargetCube, WebGLRenderTarget, WebGLRenderer, ShaderLib, UniformsLib, UniformsUtils, ShaderChunk, FogExp2, Fog, Scene, LensFlare, Sprite, LOD, SkinnedMesh, Skeleton, Bone, Mesh, LineSegments, Line, Points, Group, VideoTexture, DataTexture, CompressedTexture, CubeTexture, CanvasTexture, DepthTexture, Texture, CompressedTextureLoader, DataTextureLoader, CubeTextureLoader, TextureLoader, ObjectLoader, MaterialLoader, BufferGeometryLoader, DefaultLoadingManager, LoadingManager, JSONLoader, ImageLoader, FontLoader, FileLoader, Loader, Cache, AudioLoader, SpotLightShadow, SpotLight, PointLight, RectAreaLight, HemisphereLight, DirectionalLightShadow, DirectionalLight, AmbientLight, LightShadow, Light, StereoCamera, PerspectiveCamera, OrthographicCamera, CubeCamera, Camera, AudioListener, PositionalAudio, AudioContext, AudioAnalyser, Audio, VectorKeyframeTrack, StringKeyframeTrack, QuaternionKeyframeTrack, NumberKeyframeTrack, ColorKeyframeTrack, BooleanKeyframeTrack, PropertyMixer, PropertyBinding, KeyframeTrack, AnimationUtils, AnimationObjectGroup, AnimationMixer, AnimationClip, Uniform, InstancedBufferGeometry, BufferGeometry, GeometryIdCount, Geometry, InterleavedBufferAttribute, InstancedInterleavedBuffer, InterleavedBuffer, InstancedBufferAttribute, Face3, Object3D, Raycaster, Layers, EventDispatcher, Clock, QuaternionLinearInterpolant, LinearInterpolant, DiscreteInterpolant, CubicInterpolant, Interpolant, Triangle, _Math as Math, Spherical, Cylindrical, Plane, Frustum, Sphere, Ray, Matrix4, Matrix3, Box3, Box2, Line3, Euler, Vector4, Vector3, Vector2, Quaternion, Color, MorphBlendMesh, ImmediateRenderObject, VertexNormalsHelper, SpotLightHelper, SkeletonHelper, PointLightHelper, RectAreaLightHelper, HemisphereLightHelper, GridHelper, PolarGridHelper, FaceNormalsHelper, DirectionalLightHelper, CameraHelper, BoxHelper, ArrowHelper, AxisHelper, CatmullRomCurve3, CubicBezierCurve3, QuadraticBezierCurve3, LineCurve3, ArcCurve, EllipseCurve, SplineCurve, CubicBezierCurve, QuadraticBezierCurve, LineCurve, Shape, Path, ShapePath, Font, CurvePath, Curve, ShapeUtils, SceneUtils, WireframeGeometry, ParametricGeometry, ParametricBufferGeometry, TetrahedronGeometry, TetrahedronBufferGeometry, OctahedronGeometry, OctahedronBufferGeometry, IcosahedronGeometry, IcosahedronBufferGeometry, DodecahedronGeometry, DodecahedronBufferGeometry, PolyhedronGeometry, PolyhedronBufferGeometry, TubeGeometry, TubeBufferGeometry, TorusKnotGeometry, TorusKnotBufferGeometry, TorusGeometry, TorusBufferGeometry, TextGeometry, SphereGeometry, SphereBufferGeometry, RingGeometry, RingBufferGeometry, PlaneGeometry, PlaneBufferGeometry, LatheGeometry, LatheBufferGeometry, ShapeGeometry, ShapeBufferGeometry, ExtrudeGeometry, EdgesGeometry, ConeGeometry, ConeBufferGeometry, CylinderGeometry, CylinderBufferGeometry, CircleGeometry, CircleBufferGeometry, BoxGeometry, BoxBufferGeometry, ShadowMaterial, SpriteMaterial, RawShaderMaterial, ShaderMaterial, PointsMaterial, MultiMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshPhongMaterial, MeshToonMaterial, MeshNormalMaterial, MeshLambertMaterial, MeshDepthMaterial, MeshBasicMaterial, LineDashedMaterial, LineBasicMaterial, Material, Float64BufferAttribute, Float32BufferAttribute, Uint32BufferAttribute, Int32BufferAttribute, Uint16BufferAttribute, Int16BufferAttribute, Uint8ClampedBufferAttribute, Uint8BufferAttribute, Int8BufferAttribute, BufferAttribute, REVISION, MOUSE, CullFaceNone, CullFaceBack, CullFaceFront, CullFaceFrontBack, FrontFaceDirectionCW, FrontFaceDirectionCCW, BasicShadowMap, PCFShadowMap, PCFSoftShadowMap, FrontSide, BackSide, DoubleSide, FlatShading, SmoothShading, NoColors, FaceColors, VertexColors, NoBlending, NormalBlending, AdditiveBlending, SubtractiveBlending, MultiplyBlending, CustomBlending, AddEquation, SubtractEquation, ReverseSubtractEquation, MinEquation, MaxEquation, ZeroFactor, OneFactor, SrcColorFactor, OneMinusSrcColorFactor, SrcAlphaFactor, OneMinusSrcAlphaFactor, DstAlphaFactor, OneMinusDstAlphaFactor, DstColorFactor, OneMinusDstColorFactor, SrcAlphaSaturateFactor, NeverDepth, AlwaysDepth, LessDepth, LessEqualDepth, EqualDepth, GreaterEqualDepth, GreaterDepth, NotEqualDepth, MultiplyOperation, MixOperation, AddOperation, NoToneMapping, LinearToneMapping, ReinhardToneMapping, Uncharted2ToneMapping, CineonToneMapping, UVMapping, CubeReflectionMapping, CubeRefractionMapping, EquirectangularReflectionMapping, EquirectangularRefractionMapping, SphericalReflectionMapping, CubeUVReflectionMapping, CubeUVRefractionMapping, RepeatWrapping, ClampToEdgeWrapping, MirroredRepeatWrapping, NearestFilter, NearestMipMapNearestFilter, NearestMipMapLinearFilter, LinearFilter, LinearMipMapNearestFilter, LinearMipMapLinearFilter, UnsignedByteType, ByteType, ShortType, UnsignedShortType, IntType, UnsignedIntType, FloatType, HalfFloatType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShort565Type, UnsignedInt248Type, AlphaFormat, RGBFormat, RGBAFormat, LuminanceFormat, LuminanceAlphaFormat, RGBEFormat, DepthFormat, DepthStencilFormat, RGB_S3TC_DXT1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGB_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_PVRTC_2BPPV1_Format, RGB_ETC1_Format, LoopOnce, LoopRepeat, LoopPingPong, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, ZeroCurvatureEnding, ZeroSlopeEnding, WrapAroundEnding, TrianglesDrawMode, TriangleStripDrawMode, TriangleFanDrawMode, LinearEncoding, sRGBEncoding, GammaEncoding, RGBEEncoding, LogLuvEncoding, RGBM7Encoding, RGBM16Encoding, RGBDEncoding, BasicDepthPacking, RGBADepthPacking, BoxGeometry as CubeGeometry, Face4, LineStrip, LinePieces, MeshFaceMaterial, PointCloud, Particle, ParticleSystem, PointCloudMaterial, ParticleBasicMaterial, ParticleSystemMaterial, Vertex, DynamicBufferAttribute, Int8Attribute, Uint8Attribute, Uint8ClampedAttribute, Int16Attribute, Uint16Attribute, Int32Attribute, Uint32Attribute, Float32Attribute, Float64Attribute, ClosedSplineCurve3, SplineCurve3, Spline, BoundingBoxHelper, EdgesHelper, WireframeHelper, XHRLoader, BinaryTextureLoader, GeometryUtils, ImageUtils, Projector, CanvasRenderer };\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/three/build/three.module.js\n// module id = 0\n// module chunks = 0","/**\n * @author alteredq / http://alteredqualia.com/\n */\n\nmodule.exports = function(THREE) {\n var CopyShader = EffectComposer.CopyShader = require('three-copyshader')\n , RenderPass = EffectComposer.RenderPass = require('./lib/renderpass')(THREE)\n , ShaderPass = EffectComposer.ShaderPass = require('./lib/shaderpass')(THREE, EffectComposer)\n , MaskPass = EffectComposer.MaskPass = require('./lib/maskpass')(THREE)\n , ClearMaskPass = EffectComposer.ClearMaskPass = require('./lib/clearmaskpass')(THREE)\n\n function EffectComposer( renderer, renderTarget ) {\n this.renderer = renderer;\n\n if ( renderTarget === undefined ) {\n var width = window.innerWidth || 1;\n var height = window.innerHeight || 1;\n var parameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false };\n\n renderTarget = new THREE.WebGLRenderTarget( width, height, parameters );\n }\n\n this.renderTarget1 = renderTarget;\n this.renderTarget2 = renderTarget.clone();\n\n this.writeBuffer = this.renderTarget1;\n this.readBuffer = this.renderTarget2;\n\n this.passes = [];\n\n this.copyPass = new ShaderPass( CopyShader );\n };\n\n EffectComposer.prototype = {\n swapBuffers: function() {\n\n var tmp = this.readBuffer;\n this.readBuffer = this.writeBuffer;\n this.writeBuffer = tmp;\n\n },\n\n addPass: function ( pass ) {\n\n this.passes.push( pass );\n\n },\n\n insertPass: function ( pass, index ) {\n\n this.passes.splice( index, 0, pass );\n\n },\n\n render: function ( delta ) {\n\n this.writeBuffer = this.renderTarget1;\n this.readBuffer = this.renderTarget2;\n\n var maskActive = false;\n\n var pass, i, il = this.passes.length;\n\n for ( i = 0; i < il; i ++ ) {\n\n pass = this.passes[ i ];\n\n if ( !pass.enabled ) continue;\n\n pass.render( this.renderer, this.writeBuffer, this.readBuffer, delta, maskActive );\n\n if ( pass.needsSwap ) {\n\n if ( maskActive ) {\n\n var context = this.renderer.context;\n\n context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );\n\n this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, delta );\n\n context.stencilFunc( context.EQUAL, 1, 0xffffffff );\n\n }\n\n this.swapBuffers();\n\n }\n\n if ( pass instanceof MaskPass ) {\n\n maskActive = true;\n\n } else if ( pass instanceof ClearMaskPass ) {\n\n maskActive = false;\n\n }\n\n }\n\n },\n\n reset: function ( renderTarget ) {\n\n if ( renderTarget === undefined ) {\n\n renderTarget = this.renderTarget1.clone();\n\n renderTarget.width = window.innerWidth;\n renderTarget.height = window.innerHeight;\n\n }\n\n this.renderTarget1 = renderTarget;\n this.renderTarget2 = renderTarget.clone();\n\n this.writeBuffer = this.renderTarget1;\n this.readBuffer = this.renderTarget2;\n\n },\n\n setSize: function ( width, height ) {\n\n var renderTarget = this.renderTarget1.clone();\n\n renderTarget.width = width;\n renderTarget.height = height;\n\n this.reset( renderTarget );\n\n }\n\n };\n\n // shared ortho camera\n\n EffectComposer.camera = new THREE.OrthographicCamera( -1, 1, 1, -1, 0, 1 );\n\n EffectComposer.quad = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), null );\n\n EffectComposer.scene = new THREE.Scene();\n EffectComposer.scene.add( EffectComposer.quad );\n\n return EffectComposer\n};\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/three-effectcomposer/index.js\n// module id = 1\n// module chunks = 0","module.exports = \"\\n// we use this vertex shader for the post process steps. All we do is copy the uv value and set position appropriately\\nvarying vec2 f_uv;\\nvoid main() {\\n f_uv = uv;\\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\\n}\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/glsl/pass-vert.glsl\n// module id = 2\n// module chunks = 0","\n// this file is just for convenience. it sets up loading the mario obj and texture\n// comment\nconst THREE = require('three');\nrequire('three-obj-loader')(THREE)\n\nexport var textureLoaded = new Promise((resolve, reject) => {\n (new THREE.TextureLoader()).load(require('./assets/wahoo.bmp'), function(texture) {\n resolve(texture);\n });\n})\n\nexport var objLoaded = new Promise((resolve, reject) => {\n (new THREE.OBJLoader()).load(require('./assets/wahoo.obj'), function(obj) {\n var geo = obj.children[0].geometry;\n geo.computeBoundingSphere();\n resolve(geo);\n });\n})\n\n\n// WEBPACK FOOTER //\n// ./src/mario.js","module.exports = __webpack_public_path__ + \"./assets/wahoo-d362db.obj\";\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/assets/wahoo.obj\n// module id = 4\n// module chunks = 0","'use strict';\n\nmodule.exports = function (THREE) {\n\n /**\n * @author mrdoob / http://mrdoob.com/\n */\n THREE.OBJLoader = function (manager) {\n\n this.manager = manager !== undefined ? manager : THREE.DefaultLoadingManager;\n };\n\n THREE.OBJLoader.prototype = {\n\n constructor: THREE.OBJLoader,\n\n load: function load(url, onLoad, onProgress, onError) {\n\n var scope = this;\n\n var loader = new THREE.XHRLoader(scope.manager);\n loader.load(url, function (text) {\n\n onLoad(scope.parse(text));\n }, onProgress, onError);\n },\n\n parse: function parse(text) {\n\n console.time('OBJLoader');\n\n var object,\n objects = [];\n var geometry, material;\n\n function parseVertexIndex(value) {\n\n var index = parseInt(value);\n\n return (index >= 0 ? index - 1 : index + vertices.length / 3) * 3;\n }\n\n function parseNormalIndex(value) {\n\n var index = parseInt(value);\n\n return (index >= 0 ? index - 1 : index + normals.length / 3) * 3;\n }\n\n function parseUVIndex(value) {\n\n var index = parseInt(value);\n\n return (index >= 0 ? index - 1 : index + uvs.length / 2) * 2;\n }\n\n function addVertex(a, b, c) {\n\n geometry.vertices.push(vertices[a], vertices[a + 1], vertices[a + 2], vertices[b], vertices[b + 1], vertices[b + 2], vertices[c], vertices[c + 1], vertices[c + 2]);\n }\n\n function addNormal(a, b, c) {\n\n geometry.normals.push(normals[a], normals[a + 1], normals[a + 2], normals[b], normals[b + 1], normals[b + 2], normals[c], normals[c + 1], normals[c + 2]);\n }\n\n function addUV(a, b, c) {\n\n geometry.uvs.push(uvs[a], uvs[a + 1], uvs[b], uvs[b + 1], uvs[c], uvs[c + 1]);\n }\n\n function addFace(a, b, c, d, ua, ub, uc, ud, na, nb, nc, nd) {\n\n var ia = parseVertexIndex(a);\n var ib = parseVertexIndex(b);\n var ic = parseVertexIndex(c);\n var id;\n\n if (d === undefined) {\n\n addVertex(ia, ib, ic);\n } else {\n\n id = parseVertexIndex(d);\n\n addVertex(ia, ib, id);\n addVertex(ib, ic, id);\n }\n\n if (ua !== undefined) {\n\n ia = parseUVIndex(ua);\n ib = parseUVIndex(ub);\n ic = parseUVIndex(uc);\n\n if (d === undefined) {\n\n addUV(ia, ib, ic);\n } else {\n\n id = parseUVIndex(ud);\n\n addUV(ia, ib, id);\n addUV(ib, ic, id);\n }\n }\n\n if (na !== undefined) {\n\n ia = parseNormalIndex(na);\n ib = parseNormalIndex(nb);\n ic = parseNormalIndex(nc);\n\n if (d === undefined) {\n\n addNormal(ia, ib, ic);\n } else {\n\n id = parseNormalIndex(nd);\n\n addNormal(ia, ib, id);\n addNormal(ib, ic, id);\n }\n }\n }\n\n // create mesh if no objects in text\n\n if (/^o /gm.test(text) === false) {\n\n geometry = {\n vertices: [],\n normals: [],\n uvs: []\n };\n\n material = {\n name: ''\n };\n\n object = {\n name: '',\n geometry: geometry,\n material: material\n };\n\n objects.push(object);\n }\n\n var vertices = [];\n var normals = [];\n var uvs = [];\n\n // v float float float\n\n var vertex_pattern = /v( +[\\d|\\.|\\+|\\-|e|E]+)( +[\\d|\\.|\\+|\\-|e|E]+)( +[\\d|\\.|\\+|\\-|e|E]+)/;\n\n // vn float float float\n\n var normal_pattern = /vn( +[\\d|\\.|\\+|\\-|e|E]+)( +[\\d|\\.|\\+|\\-|e|E]+)( +[\\d|\\.|\\+|\\-|e|E]+)/;\n\n // vt float float\n\n var uv_pattern = /vt( +[\\d|\\.|\\+|\\-|e|E]+)( +[\\d|\\.|\\+|\\-|e|E]+)/;\n\n // f vertex vertex vertex ...\n\n var face_pattern1 = /f( +-?\\d+)( +-?\\d+)( +-?\\d+)( +-?\\d+)?/;\n\n // f vertex/uv vertex/uv vertex/uv ...\n\n var face_pattern2 = /f( +(-?\\d+)\\/(-?\\d+))( +(-?\\d+)\\/(-?\\d+))( +(-?\\d+)\\/(-?\\d+))( +(-?\\d+)\\/(-?\\d+))?/;\n\n // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...\n\n var face_pattern3 = /f( +(-?\\d+)\\/(-?\\d+)\\/(-?\\d+))( +(-?\\d+)\\/(-?\\d+)\\/(-?\\d+))( +(-?\\d+)\\/(-?\\d+)\\/(-?\\d+))( +(-?\\d+)\\/(-?\\d+)\\/(-?\\d+))?/;\n\n // f vertex//normal vertex//normal vertex//normal ...\n\n var face_pattern4 = /f( +(-?\\d+)\\/\\/(-?\\d+))( +(-?\\d+)\\/\\/(-?\\d+))( +(-?\\d+)\\/\\/(-?\\d+))( +(-?\\d+)\\/\\/(-?\\d+))?/;\n\n //\n\n var lines = text.split('\\n');\n\n for (var i = 0; i < lines.length; i++) {\n\n var line = lines[i];\n line = line.trim();\n\n var result;\n\n if (line.length === 0 || line.charAt(0) === '#') {\n\n continue;\n } else if ((result = vertex_pattern.exec(line)) !== null) {\n\n // [\"v 1.0 2.0 3.0\", \"1.0\", \"2.0\", \"3.0\"]\n\n vertices.push(parseFloat(result[1]), parseFloat(result[2]), parseFloat(result[3]));\n } else if ((result = normal_pattern.exec(line)) !== null) {\n\n // [\"vn 1.0 2.0 3.0\", \"1.0\", \"2.0\", \"3.0\"]\n\n normals.push(parseFloat(result[1]), parseFloat(result[2]), parseFloat(result[3]));\n } else if ((result = uv_pattern.exec(line)) !== null) {\n\n // [\"vt 0.1 0.2\", \"0.1\", \"0.2\"]\n\n uvs.push(parseFloat(result[1]), parseFloat(result[2]));\n } else if ((result = face_pattern1.exec(line)) !== null) {\n\n // [\"f 1 2 3\", \"1\", \"2\", \"3\", undefined]\n\n addFace(result[1], result[2], result[3], result[4]);\n } else if ((result = face_pattern2.exec(line)) !== null) {\n\n // [\"f 1/1 2/2 3/3\", \" 1/1\", \"1\", \"1\", \" 2/2\", \"2\", \"2\", \" 3/3\", \"3\", \"3\", undefined, undefined, undefined]\n\n addFace(result[2], result[5], result[8], result[11], result[3], result[6], result[9], result[12]);\n } else if ((result = face_pattern3.exec(line)) !== null) {\n\n // [\"f 1/1/1 2/2/2 3/3/3\", \" 1/1/1\", \"1\", \"1\", \"1\", \" 2/2/2\", \"2\", \"2\", \"2\", \" 3/3/3\", \"3\", \"3\", \"3\", undefined, undefined, undefined, undefined]\n\n addFace(result[2], result[6], result[10], result[14], result[3], result[7], result[11], result[15], result[4], result[8], result[12], result[16]);\n } else if ((result = face_pattern4.exec(line)) !== null) {\n\n // [\"f 1//1 2//2 3//3\", \" 1//1\", \"1\", \"1\", \" 2//2\", \"2\", \"2\", \" 3//3\", \"3\", \"3\", undefined, undefined, undefined]\n\n addFace(result[2], result[5], result[8], result[11], undefined, undefined, undefined, undefined, result[3], result[6], result[9], result[12]);\n } else if (/^o /.test(line)) {\n\n geometry = {\n vertices: [],\n normals: [],\n uvs: []\n };\n\n material = {\n name: ''\n };\n\n object = {\n name: line.substring(2).trim(),\n geometry: geometry,\n material: material\n };\n\n objects.push(object);\n } else if (/^g /.test(line)) {\n\n // group\n\n } else if (/^usemtl /.test(line)) {\n\n // material\n\n material.name = line.substring(7).trim();\n } else if (/^mtllib /.test(line)) {\n\n // mtl file\n\n } else if (/^s /.test(line)) {\n\n // smooth shading\n\n } else {\n\n // console.log( \"THREE.OBJLoader: Unhandled line \" + line );\n\n }\n }\n\n var container = new THREE.Object3D();\n var l;\n\n for (i = 0, l = objects.length; i < l; i++) {\n\n object = objects[i];\n geometry = object.geometry;\n\n var buffergeometry = new THREE.BufferGeometry();\n\n buffergeometry.addAttribute('position', new THREE.BufferAttribute(new Float32Array(geometry.vertices), 3));\n\n if (geometry.normals.length > 0) {\n\n buffergeometry.addAttribute('normal', new THREE.BufferAttribute(new Float32Array(geometry.normals), 3));\n }\n\n if (geometry.uvs.length > 0) {\n\n buffergeometry.addAttribute('uv', new THREE.BufferAttribute(new Float32Array(geometry.uvs), 2));\n }\n\n material = new THREE.MeshLambertMaterial({\n color: 0xff0000\n });\n material.name = object.material.name;\n\n var mesh = new THREE.Mesh(buffergeometry, material);\n mesh.name = object.name;\n\n container.add(mesh);\n }\n\n console.timeEnd('OBJLoader');\n\n return container;\n }\n\n };\n};\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/three-obj-loader/dist/index.js\n// module id = 5\n// module chunks = 0","import * as Shaders from './shaders'\nimport * as Post from './post'\nimport DAT from 'dat-gui'\n\nDAT.GUI.prototype.removeFolder = function(name) {\n var folder = this.__folders[name];\n if (!folder) {\n return;\n }\n folder.close();\n this.__ul.removeChild(folder.domElement.parentNode);\n delete this.__folders[name];\n this.onResize();\n}\n\nDAT.GUI.prototype.emptyFolder = function(name) {\n var folder = this.__folders[name];\n if (!folder) {\n return;\n }\n for (let i = 0; i < folder.__controllers.length; ++i) {\n folder.__controllers[i].remove();\n }\n folder.__controllers.length = 0;\n this.onResize();\n}\n\nexport function setupGUI(shaderSet, postProcessSet) {\n var gui = new DAT.GUI();\n var opts = { shader: null, post: null }\n\n var shaderControl = gui.add(opts, 'shader', Object.keys(Shaders)).onChange(name => {\n setShader(name);\n });\n var shaderFolder = gui.addFolder('Shader Settings');\n shaderFolder.open();\n\n var postControl = gui.add(opts, 'post', Object.keys(Post)).onChange(name => {\n setPostProcess(name);\n })\n var postFolder = gui.addFolder('Post Process Settings');\n postFolder.open();\n\n function setShader(name) {\n gui.emptyFolder('Shader Settings');\n opts.shader = name;\n shaderControl.updateDisplay();\n shaderSet(Shaders[name], shaderFolder);\n }\n\n function setPostProcess(name) {\n gui.emptyFolder('Post Process Settings');\n opts.post = name;\n postControl.updateDisplay();\n postProcessSet(Post[name], postFolder);\n }\n\n setShader(Object.keys(Shaders)[0]);\n setPostProcess(Object.keys(Post)[0]);\n\n return {\n setShader,\n setPostProcess\n }\n}\n\n\n// WEBPACK FOOTER //\n// ./src/setup.js","module.exports = __webpack_public_path__ + \"index.html\";\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/file-loader?name=[name].[ext]!./index.html\n// module id = 7\n// module chunks = 0","// stats.js - http://github.com/mrdoob/stats.js\nvar Stats=function(){var l=Date.now(),m=l,g=0,n=Infinity,o=0,h=0,p=Infinity,q=0,r=0,s=0,f=document.createElement(\"div\");f.id=\"stats\";f.addEventListener(\"mousedown\",function(b){b.preventDefault();t(++s%2)},!1);f.style.cssText=\"width:80px;opacity:0.9;cursor:pointer\";var a=document.createElement(\"div\");a.id=\"fps\";a.style.cssText=\"padding:0 0 3px 3px;text-align:left;background-color:#002\";f.appendChild(a);var i=document.createElement(\"div\");i.id=\"fpsText\";i.style.cssText=\"color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px\";\ni.innerHTML=\"FPS\";a.appendChild(i);var c=document.createElement(\"div\");c.id=\"fpsGraph\";c.style.cssText=\"position:relative;width:74px;height:30px;background-color:#0ff\";for(a.appendChild(c);74>c.children.length;){var j=document.createElement(\"span\");j.style.cssText=\"width:1px;height:30px;float:left;background-color:#113\";c.appendChild(j)}var d=document.createElement(\"div\");d.id=\"ms\";d.style.cssText=\"padding:0 0 3px 3px;text-align:left;background-color:#020;display:none\";f.appendChild(d);var k=document.createElement(\"div\");\nk.id=\"msText\";k.style.cssText=\"color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px\";k.innerHTML=\"MS\";d.appendChild(k);var e=document.createElement(\"div\");e.id=\"msGraph\";e.style.cssText=\"position:relative;width:74px;height:30px;background-color:#0f0\";for(d.appendChild(e);74>e.children.length;)j=document.createElement(\"span\"),j.style.cssText=\"width:1px;height:30px;float:left;background-color:#131\",e.appendChild(j);var t=function(b){s=b;switch(s){case 0:a.style.display=\n\"block\";d.style.display=\"none\";break;case 1:a.style.display=\"none\",d.style.display=\"block\"}};return{REVISION:12,domElement:f,setMode:t,begin:function(){l=Date.now()},end:function(){var b=Date.now();g=b-l;n=Math.min(n,g);o=Math.max(o,g);k.textContent=g+\" MS (\"+n+\"-\"+o+\")\";var a=Math.min(30,30-30*(g/200));e.appendChild(e.firstChild).style.height=a+\"px\";r++;b>m+1E3&&(h=Math.round(1E3*r/(b-m)),p=Math.min(p,h),q=Math.max(q,h),i.textContent=h+\" FPS (\"+p+\"-\"+q+\")\",a=Math.min(30,30-30*(h/100)),c.appendChild(c.firstChild).style.height=\na+\"px\",m=b,r=0);return b},update:function(){l=this.end()}}};\"object\"===typeof module&&(module.exports=Stats);\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/stats-js/build/stats.min.js\n// module id = 8\n// module chunks = 0","module.exports = function( THREE ) {\n\t/**\n\t * @author qiao / https://github.com/qiao\n\t * @author mrdoob / http://mrdoob.com\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author WestLangley / http://github.com/WestLangley\n\t * @author erich666 / http://erichaines.com\n\t */\n\n// This set of controls performs orbiting, dollying (zooming), and panning.\n// Unlike TrackballControls, it maintains the \"up\" direction object.up (+Y by default).\n//\n// Orbit - left mouse / touch: one finger move\n// Zoom - middle mouse, or mousewheel / touch: two finger spread or squish\n// Pan - right mouse, or arrow keys / touch: three finter swipe\n\n\tfunction OrbitControls( object, domElement ) {\n\n\t\tthis.object = object;\n\n\t\tthis.domElement = ( domElement !== undefined ) ? domElement : document;\n\n\t\t// Set to false to disable this control\n\t\tthis.enabled = true;\n\n\t\t// \"target\" sets the location of focus, where the object orbits around\n\t\tthis.target = new THREE.Vector3();\n\n\t\t// How far you can dolly in and out ( PerspectiveCamera only )\n\t\tthis.minDistance = 0;\n\t\tthis.maxDistance = Infinity;\n\n\t\t// How far you can zoom in and out ( OrthographicCamera only )\n\t\tthis.minZoom = 0;\n\t\tthis.maxZoom = Infinity;\n\n\t\t// How far you can orbit vertically, upper and lower limits.\n\t\t// Range is 0 to Math.PI radians.\n\t\tthis.minPolarAngle = 0; // radians\n\t\tthis.maxPolarAngle = Math.PI; // radians\n\n\t\t// How far you can orbit horizontally, upper and lower limits.\n\t\t// If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].\n\t\tthis.minAzimuthAngle = - Infinity; // radians\n\t\tthis.maxAzimuthAngle = Infinity; // radians\n\n\t\t// Set to true to enable damping (inertia)\n\t\t// If damping is enabled, you must call controls.update() in your animation loop\n\t\tthis.enableDamping = false;\n\t\tthis.dampingFactor = 0.25;\n\n\t\t// This option actually enables dollying in and out; left as \"zoom\" for backwards compatibility.\n\t\t// Set to false to disable zooming\n\t\tthis.enableZoom = true;\n\t\tthis.zoomSpeed = 1.0;\n\n\t\t// Set to false to disable rotating\n\t\tthis.enableRotate = true;\n\t\tthis.rotateSpeed = 1.0;\n\n\t\t// Set to false to disable panning\n\t\tthis.enablePan = true;\n\t\tthis.keyPanSpeed = 7.0;\t// pixels moved per arrow key push\n\n\t\t// Set to true to automatically rotate around the target\n\t\t// If auto-rotate is enabled, you must call controls.update() in your animation loop\n\t\tthis.autoRotate = false;\n\t\tthis.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60\n\n\t\t// Set to false to disable use of the keys\n\t\tthis.enableKeys = true;\n\n\t\t// The four arrow keys\n\t\tthis.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };\n\n\t\t// Mouse buttons\n\t\tthis.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT };\n\n\t\t// for reset\n\t\tthis.target0 = this.target.clone();\n\t\tthis.position0 = this.object.position.clone();\n\t\tthis.zoom0 = this.object.zoom;\n\n\t\t//\n\t\t// public methods\n\t\t//\n\n\t\tthis.getPolarAngle = function () {\n\n\t\t\treturn spherical.phi;\n\n\t\t};\n\n\t\tthis.getAzimuthalAngle = function () {\n\n\t\t\treturn spherical.theta;\n\n\t\t};\n\n\t\tthis.reset = function () {\n\n\t\t\tscope.target.copy( scope.target0 );\n\t\t\tscope.object.position.copy( scope.position0 );\n\t\t\tscope.object.zoom = scope.zoom0;\n\n\t\t\tscope.object.updateProjectionMatrix();\n\t\t\tscope.dispatchEvent( changeEvent );\n\n\t\t\tscope.update();\n\n\t\t\tstate = STATE.NONE;\n\n\t\t};\n\n\t\t// this method is exposed, but perhaps it would be better if we can make it private...\n\t\tthis.update = function() {\n\n\t\t\tvar offset = new THREE.Vector3();\n\n\t\t\t// so camera.up is the orbit axis\n\t\t\tvar quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) );\n\t\t\tvar quatInverse = quat.clone().inverse();\n\n\t\t\tvar lastPosition = new THREE.Vector3();\n\t\t\tvar lastQuaternion = new THREE.Quaternion();\n\n\t\t\treturn function update () {\n\n\t\t\t\tvar position = scope.object.position;\n\n\t\t\t\toffset.copy( position ).sub( scope.target );\n\n\t\t\t\t// rotate offset to \"y-axis-is-up\" space\n\t\t\t\toffset.applyQuaternion( quat );\n\n\t\t\t\t// angle from z-axis around y-axis\n\t\t\t\tspherical.setFromVector3( offset );\n\n\t\t\t\tif ( scope.autoRotate && state === STATE.NONE ) {\n\n\t\t\t\t\trotateLeft( getAutoRotationAngle() );\n\n\t\t\t\t}\n\n\t\t\t\tspherical.theta += sphericalDelta.theta;\n\t\t\t\tspherical.phi += sphericalDelta.phi;\n\n\t\t\t\t// restrict theta to be between desired limits\n\t\t\t\tspherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) );\n\n\t\t\t\t// restrict phi to be between desired limits\n\t\t\t\tspherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) );\n\n\t\t\t\tspherical.makeSafe();\n\n\n\t\t\t\tspherical.radius *= scale;\n\n\t\t\t\t// restrict radius to be between desired limits\n\t\t\t\tspherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) );\n\n\t\t\t\t// move target to panned location\n\t\t\t\tscope.target.add( panOffset );\n\n\t\t\t\toffset.setFromSpherical( spherical );\n\n\t\t\t\t// rotate offset back to \"camera-up-vector-is-up\" space\n\t\t\t\toffset.applyQuaternion( quatInverse );\n\n\t\t\t\tposition.copy( scope.target ).add( offset );\n\n\t\t\t\tscope.object.lookAt( scope.target );\n\n\t\t\t\tif ( scope.enableDamping === true ) {\n\n\t\t\t\t\tsphericalDelta.theta *= ( 1 - scope.dampingFactor );\n\t\t\t\t\tsphericalDelta.phi *= ( 1 - scope.dampingFactor );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tsphericalDelta.set( 0, 0, 0 );\n\n\t\t\t\t}\n\n\t\t\t\tscale = 1;\n\t\t\t\tpanOffset.set( 0, 0, 0 );\n\n\t\t\t\t// update condition is:\n\t\t\t\t// min(camera displacement, camera rotation in radians)^2 > EPS\n\t\t\t\t// using small-angle approximation cos(x/2) = 1 - x^2 / 8\n\n\t\t\t\tif ( zoomChanged ||\n\t\t\t\t\tlastPosition.distanceToSquared( scope.object.position ) > EPS ||\n\t\t\t\t\t8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) {\n\n\t\t\t\t\tscope.dispatchEvent( changeEvent );\n\n\t\t\t\t\tlastPosition.copy( scope.object.position );\n\t\t\t\t\tlastQuaternion.copy( scope.object.quaternion );\n\t\t\t\t\tzoomChanged = false;\n\n\t\t\t\t\treturn true;\n\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\n\t\t\t};\n\n\t\t}();\n\n\t\tthis.dispose = function() {\n\n\t\t\tscope.domElement.removeEventListener( 'contextmenu', onContextMenu, false );\n\t\t\tscope.domElement.removeEventListener( 'mousedown', onMouseDown, false );\n\t\t\tscope.domElement.removeEventListener( 'wheel', onMouseWheel, false );\n\n\t\t\tscope.domElement.removeEventListener( 'touchstart', onTouchStart, false );\n\t\t\tscope.domElement.removeEventListener( 'touchend', onTouchEnd, false );\n\t\t\tscope.domElement.removeEventListener( 'touchmove', onTouchMove, false );\n\n\t\t\tdocument.removeEventListener( 'mousemove', onMouseMove, false );\n\t\t\tdocument.removeEventListener( 'mouseup', onMouseUp, false );\n\n\t\t\twindow.removeEventListener( 'keydown', onKeyDown, false );\n\n\t\t\t//scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?\n\n\t\t};\n\n\t\t//\n\t\t// internals\n\t\t//\n\n\t\tvar scope = this;\n\n\t\tvar changeEvent = { type: 'change' };\n\t\tvar startEvent = { type: 'start' };\n\t\tvar endEvent = { type: 'end' };\n\n\t\tvar STATE = { NONE : - 1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };\n\n\t\tvar state = STATE.NONE;\n\n\t\tvar EPS = 0.000001;\n\n\t\t// current position in spherical coordinates\n\t\tvar spherical = new THREE.Spherical();\n\t\tvar sphericalDelta = new THREE.Spherical();\n\n\t\tvar scale = 1;\n\t\tvar panOffset = new THREE.Vector3();\n\t\tvar zoomChanged = false;\n\n\t\tvar rotateStart = new THREE.Vector2();\n\t\tvar rotateEnd = new THREE.Vector2();\n\t\tvar rotateDelta = new THREE.Vector2();\n\n\t\tvar panStart = new THREE.Vector2();\n\t\tvar panEnd = new THREE.Vector2();\n\t\tvar panDelta = new THREE.Vector2();\n\n\t\tvar dollyStart = new THREE.Vector2();\n\t\tvar dollyEnd = new THREE.Vector2();\n\t\tvar dollyDelta = new THREE.Vector2();\n\n\t\tfunction getAutoRotationAngle() {\n\n\t\t\treturn 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;\n\n\t\t}\n\n\t\tfunction getZoomScale() {\n\n\t\t\treturn Math.pow( 0.95, scope.zoomSpeed );\n\n\t\t}\n\n\t\tfunction rotateLeft( angle ) {\n\n\t\t\tsphericalDelta.theta -= angle;\n\n\t\t}\n\n\t\tfunction rotateUp( angle ) {\n\n\t\t\tsphericalDelta.phi -= angle;\n\n\t\t}\n\n\t\tvar panLeft = function() {\n\n\t\t\tvar v = new THREE.Vector3();\n\n\t\t\treturn function panLeft( distance, objectMatrix ) {\n\n\t\t\t\tv.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix\n\t\t\t\tv.multiplyScalar( - distance );\n\n\t\t\t\tpanOffset.add( v );\n\n\t\t\t};\n\n\t\t}();\n\n\t\tvar panUp = function() {\n\n\t\t\tvar v = new THREE.Vector3();\n\n\t\t\treturn function panUp( distance, objectMatrix ) {\n\n\t\t\t\tv.setFromMatrixColumn( objectMatrix, 1 ); // get Y column of objectMatrix\n\t\t\t\tv.multiplyScalar( distance );\n\n\t\t\t\tpanOffset.add( v );\n\n\t\t\t};\n\n\t\t}();\n\n\t\t// deltaX and deltaY are in pixels; right and down are positive\n\t\tvar pan = function() {\n\n\t\t\tvar offset = new THREE.Vector3();\n\n\t\t\treturn function pan ( deltaX, deltaY ) {\n\n\t\t\t\tvar element = scope.domElement === document ? scope.domElement.body : scope.domElement;\n\n\t\t\t\tif ( scope.object instanceof THREE.PerspectiveCamera ) {\n\n\t\t\t\t\t// perspective\n\t\t\t\t\tvar position = scope.object.position;\n\t\t\t\t\toffset.copy( position ).sub( scope.target );\n\t\t\t\t\tvar targetDistance = offset.length();\n\n\t\t\t\t\t// half of the fov is center to top of screen\n\t\t\t\t\ttargetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );\n\n\t\t\t\t\t// we actually don't use screenWidth, since perspective camera is fixed to screen height\n\t\t\t\t\tpanLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix );\n\t\t\t\t\tpanUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix );\n\n\t\t\t\t} else if ( scope.object instanceof THREE.OrthographicCamera ) {\n\n\t\t\t\t\t// orthographic\n\t\t\t\t\tpanLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix );\n\t\t\t\t\tpanUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// camera neither orthographic nor perspective\n\t\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );\n\t\t\t\t\tscope.enablePan = false;\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}();\n\n\t\tfunction dollyIn( dollyScale ) {\n\n\t\t\tif ( scope.object instanceof THREE.PerspectiveCamera ) {\n\n\t\t\t\tscale /= dollyScale;\n\n\t\t\t} else if ( scope.object instanceof THREE.OrthographicCamera ) {\n\n\t\t\t\tscope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) );\n\t\t\t\tscope.object.updateProjectionMatrix();\n\t\t\t\tzoomChanged = true;\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );\n\t\t\t\tscope.enableZoom = false;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction dollyOut( dollyScale ) {\n\n\t\t\tif ( scope.object instanceof THREE.PerspectiveCamera ) {\n\n\t\t\t\tscale *= dollyScale;\n\n\t\t\t} else if ( scope.object instanceof THREE.OrthographicCamera ) {\n\n\t\t\t\tscope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) );\n\t\t\t\tscope.object.updateProjectionMatrix();\n\t\t\t\tzoomChanged = true;\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );\n\t\t\t\tscope.enableZoom = false;\n\n\t\t\t}\n\n\t\t}\n\n\t\t//\n\t\t// event callbacks - update the object state\n\t\t//\n\n\t\tfunction handleMouseDownRotate( event ) {\n\n\t\t\t//console.log( 'handleMouseDownRotate' );\n\n\t\t\trotateStart.set( event.clientX, event.clientY );\n\n\t\t}\n\n\t\tfunction handleMouseDownDolly( event ) {\n\n\t\t\t//console.log( 'handleMouseDownDolly' );\n\n\t\t\tdollyStart.set( event.clientX, event.clientY );\n\n\t\t}\n\n\t\tfunction handleMouseDownPan( event ) {\n\n\t\t\t//console.log( 'handleMouseDownPan' );\n\n\t\t\tpanStart.set( event.clientX, event.clientY );\n\n\t\t}\n\n\t\tfunction handleMouseMoveRotate( event ) {\n\n\t\t\t//console.log( 'handleMouseMoveRotate' );\n\n\t\t\trotateEnd.set( event.clientX, event.clientY );\n\t\t\trotateDelta.subVectors( rotateEnd, rotateStart );\n\n\t\t\tvar element = scope.domElement === document ? scope.domElement.body : scope.domElement;\n\n\t\t\t// rotating across whole screen goes 360 degrees around\n\t\t\trotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );\n\n\t\t\t// rotating up and down along whole screen attempts to go 360, but limited to 180\n\t\t\trotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );\n\n\t\t\trotateStart.copy( rotateEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleMouseMoveDolly( event ) {\n\n\t\t\t//console.log( 'handleMouseMoveDolly' );\n\n\t\t\tdollyEnd.set( event.clientX, event.clientY );\n\n\t\t\tdollyDelta.subVectors( dollyEnd, dollyStart );\n\n\t\t\tif ( dollyDelta.y > 0 ) {\n\n\t\t\t\tdollyIn( getZoomScale() );\n\n\t\t\t} else if ( dollyDelta.y < 0 ) {\n\n\t\t\t\tdollyOut( getZoomScale() );\n\n\t\t\t}\n\n\t\t\tdollyStart.copy( dollyEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleMouseMovePan( event ) {\n\n\t\t\t//console.log( 'handleMouseMovePan' );\n\n\t\t\tpanEnd.set( event.clientX, event.clientY );\n\n\t\t\tpanDelta.subVectors( panEnd, panStart );\n\n\t\t\tpan( panDelta.x, panDelta.y );\n\n\t\t\tpanStart.copy( panEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleMouseUp( event ) {\n\n\t\t\t//console.log( 'handleMouseUp' );\n\n\t\t}\n\n\t\tfunction handleMouseWheel( event ) {\n\n\t\t\t//console.log( 'handleMouseWheel' );\n\n\t\t\tif ( event.deltaY < 0 ) {\n\n\t\t\t\tdollyOut( getZoomScale() );\n\n\t\t\t} else if ( event.deltaY > 0 ) {\n\n\t\t\t\tdollyIn( getZoomScale() );\n\n\t\t\t}\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleKeyDown( event ) {\n\n\t\t\t//console.log( 'handleKeyDown' );\n\n\t\t\tswitch ( event.keyCode ) {\n\n\t\t\t\tcase scope.keys.UP:\n\t\t\t\t\tpan( 0, scope.keyPanSpeed );\n\t\t\t\t\tscope.update();\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase scope.keys.BOTTOM:\n\t\t\t\t\tpan( 0, - scope.keyPanSpeed );\n\t\t\t\t\tscope.update();\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase scope.keys.LEFT:\n\t\t\t\t\tpan( scope.keyPanSpeed, 0 );\n\t\t\t\t\tscope.update();\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase scope.keys.RIGHT:\n\t\t\t\t\tpan( - scope.keyPanSpeed, 0 );\n\t\t\t\t\tscope.update();\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction handleTouchStartRotate( event ) {\n\n\t\t\t//console.log( 'handleTouchStartRotate' );\n\n\t\t\trotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );\n\n\t\t}\n\n\t\tfunction handleTouchStartDolly( event ) {\n\n\t\t\t//console.log( 'handleTouchStartDolly' );\n\n\t\t\tvar dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;\n\t\t\tvar dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;\n\n\t\t\tvar distance = Math.sqrt( dx * dx + dy * dy );\n\n\t\t\tdollyStart.set( 0, distance );\n\n\t\t}\n\n\t\tfunction handleTouchStartPan( event ) {\n\n\t\t\t//console.log( 'handleTouchStartPan' );\n\n\t\t\tpanStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );\n\n\t\t}\n\n\t\tfunction handleTouchMoveRotate( event ) {\n\n\t\t\t//console.log( 'handleTouchMoveRotate' );\n\n\t\t\trotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );\n\t\t\trotateDelta.subVectors( rotateEnd, rotateStart );\n\n\t\t\tvar element = scope.domElement === document ? scope.domElement.body : scope.domElement;\n\n\t\t\t// rotating across whole screen goes 360 degrees around\n\t\t\trotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );\n\n\t\t\t// rotating up and down along whole screen attempts to go 360, but limited to 180\n\t\t\trotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );\n\n\t\t\trotateStart.copy( rotateEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleTouchMoveDolly( event ) {\n\n\t\t\t//console.log( 'handleTouchMoveDolly' );\n\n\t\t\tvar dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;\n\t\t\tvar dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;\n\n\t\t\tvar distance = Math.sqrt( dx * dx + dy * dy );\n\n\t\t\tdollyEnd.set( 0, distance );\n\n\t\t\tdollyDelta.subVectors( dollyEnd, dollyStart );\n\n\t\t\tif ( dollyDelta.y > 0 ) {\n\n\t\t\t\tdollyOut( getZoomScale() );\n\n\t\t\t} else if ( dollyDelta.y < 0 ) {\n\n\t\t\t\tdollyIn( getZoomScale() );\n\n\t\t\t}\n\n\t\t\tdollyStart.copy( dollyEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleTouchMovePan( event ) {\n\n\t\t\t//console.log( 'handleTouchMovePan' );\n\n\t\t\tpanEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );\n\n\t\t\tpanDelta.subVectors( panEnd, panStart );\n\n\t\t\tpan( panDelta.x, panDelta.y );\n\n\t\t\tpanStart.copy( panEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleTouchEnd( event ) {\n\n\t\t\t//console.log( 'handleTouchEnd' );\n\n\t\t}\n\n\t\t//\n\t\t// event handlers - FSM: listen for events and reset state\n\t\t//\n\n\t\tfunction onMouseDown( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\tevent.preventDefault();\n\n\t\t\tif ( event.button === scope.mouseButtons.ORBIT ) {\n\n\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\thandleMouseDownRotate( event );\n\n\t\t\t\tstate = STATE.ROTATE;\n\n\t\t\t} else if ( event.button === scope.mouseButtons.ZOOM ) {\n\n\t\t\t\tif ( scope.enableZoom === false ) return;\n\n\t\t\t\thandleMouseDownDolly( event );\n\n\t\t\t\tstate = STATE.DOLLY;\n\n\t\t\t} else if ( event.button === scope.mouseButtons.PAN ) {\n\n\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\thandleMouseDownPan( event );\n\n\t\t\t\tstate = STATE.PAN;\n\n\t\t\t}\n\n\t\t\tif ( state !== STATE.NONE ) {\n\n\t\t\t\tdocument.addEventListener( 'mousemove', onMouseMove, false );\n\t\t\t\tdocument.addEventListener( 'mouseup', onMouseUp, false );\n\n\t\t\t\tscope.dispatchEvent( startEvent );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onMouseMove( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\tevent.preventDefault();\n\n\t\t\tif ( state === STATE.ROTATE ) {\n\n\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\thandleMouseMoveRotate( event );\n\n\t\t\t} else if ( state === STATE.DOLLY ) {\n\n\t\t\t\tif ( scope.enableZoom === false ) return;\n\n\t\t\t\thandleMouseMoveDolly( event );\n\n\t\t\t} else if ( state === STATE.PAN ) {\n\n\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\thandleMouseMovePan( event );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onMouseUp( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\thandleMouseUp( event );\n\n\t\t\tdocument.removeEventListener( 'mousemove', onMouseMove, false );\n\t\t\tdocument.removeEventListener( 'mouseup', onMouseUp, false );\n\n\t\t\tscope.dispatchEvent( endEvent );\n\n\t\t\tstate = STATE.NONE;\n\n\t\t}\n\n\t\tfunction onMouseWheel( event ) {\n\n\t\t\tif ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return;\n\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\n\t\t\thandleMouseWheel( event );\n\n\t\t\tscope.dispatchEvent( startEvent ); // not sure why these are here...\n\t\t\tscope.dispatchEvent( endEvent );\n\n\t\t}\n\n\t\tfunction onKeyDown( event ) {\n\n\t\t\tif ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return;\n\n\t\t\thandleKeyDown( event );\n\n\t\t}\n\n\t\tfunction onTouchStart( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\tswitch ( event.touches.length ) {\n\n\t\t\t\tcase 1:\t// one-fingered touch: rotate\n\n\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\thandleTouchStartRotate( event );\n\n\t\t\t\t\tstate = STATE.TOUCH_ROTATE;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 2:\t// two-fingered touch: dolly\n\n\t\t\t\t\tif ( scope.enableZoom === false ) return;\n\n\t\t\t\t\thandleTouchStartDolly( event );\n\n\t\t\t\t\tstate = STATE.TOUCH_DOLLY;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 3: // three-fingered touch: pan\n\n\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\thandleTouchStartPan( event );\n\n\t\t\t\t\tstate = STATE.TOUCH_PAN;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t}\n\n\t\t\tif ( state !== STATE.NONE ) {\n\n\t\t\t\tscope.dispatchEvent( startEvent );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onTouchMove( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\n\t\t\tswitch ( event.touches.length ) {\n\n\t\t\t\tcase 1: // one-fingered touch: rotate\n\n\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\t\t\t\t\tif ( state !== STATE.TOUCH_ROTATE ) return; // is this needed?...\n\n\t\t\t\t\thandleTouchMoveRotate( event );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 2: // two-fingered touch: dolly\n\n\t\t\t\t\tif ( scope.enableZoom === false ) return;\n\t\t\t\t\tif ( state !== STATE.TOUCH_DOLLY ) return; // is this needed?...\n\n\t\t\t\t\thandleTouchMoveDolly( event );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 3: // three-fingered touch: pan\n\n\t\t\t\t\tif ( scope.enablePan === false ) return;\n\t\t\t\t\tif ( state !== STATE.TOUCH_PAN ) return; // is this needed?...\n\n\t\t\t\t\thandleTouchMovePan( event );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onTouchEnd( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\thandleTouchEnd( event );\n\n\t\t\tscope.dispatchEvent( endEvent );\n\n\t\t\tstate = STATE.NONE;\n\n\t\t}\n\n\t\tfunction onContextMenu( event ) {\n\n\t\t\tevent.preventDefault();\n\n\t\t}\n\n\t\t//\n\n\t\tscope.domElement.addEventListener( 'contextmenu', onContextMenu, false );\n\n\t\tscope.domElement.addEventListener( 'mousedown', onMouseDown, false );\n\t\tscope.domElement.addEventListener( 'wheel', onMouseWheel, false );\n\n\t\tscope.domElement.addEventListener( 'touchstart', onTouchStart, false );\n\t\tscope.domElement.addEventListener( 'touchend', onTouchEnd, false );\n\t\tscope.domElement.addEventListener( 'touchmove', onTouchMove, false );\n\n\t\twindow.addEventListener( 'keydown', onKeyDown, false );\n\n\t\t// force an update at start\n\n\t\tthis.update();\n\n\t};\n\n\tOrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );\n\tOrbitControls.prototype.constructor = OrbitControls;\n\n\tObject.defineProperties( OrbitControls.prototype, {\n\n\t\tcenter: {\n\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.OrbitControls: .center has been renamed to .target' );\n\t\t\t\treturn this.target;\n\n\t\t\t}\n\n\t\t},\n\n\t\t// backward compatibility\n\n\t\tnoZoom: {\n\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );\n\t\t\t\treturn ! this.enableZoom;\n\n\t\t\t},\n\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );\n\t\t\t\tthis.enableZoom = ! value;\n\n\t\t\t}\n\n\t\t},\n\n\t\tnoRotate: {\n\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );\n\t\t\t\treturn ! this.enableRotate;\n\n\t\t\t},\n\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );\n\t\t\t\tthis.enableRotate = ! value;\n\n\t\t\t}\n\n\t\t},\n\n\t\tnoPan: {\n\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );\n\t\t\t\treturn ! this.enablePan;\n\n\t\t\t},\n\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );\n\t\t\t\tthis.enablePan = ! value;\n\n\t\t\t}\n\n\t\t},\n\n\t\tnoKeys: {\n\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );\n\t\t\t\treturn ! this.enableKeys;\n\n\t\t\t},\n\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );\n\t\t\t\tthis.enableKeys = ! value;\n\n\t\t\t}\n\n\t\t},\n\n\t\tstaticMoving : {\n\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );\n\t\t\t\treturn ! this.enableDamping;\n\n\t\t\t},\n\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );\n\t\t\t\tthis.enableDamping = ! value;\n\n\t\t\t}\n\n\t\t},\n\n\t\tdynamicDampingFactor : {\n\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );\n\t\t\t\treturn this.dampingFactor;\n\n\t\t\t},\n\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );\n\t\t\t\tthis.dampingFactor = value;\n\n\t\t\t}\n\n\t\t}\n\n\t} );\n\n\treturn OrbitControls;\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/three-orbit-controls/index.js\n// module id = 9\n// module chunks = 0","\n// this file is just for convenience. it sets up loading the mario obj and texture\n\nconst THREE = require('three');\nrequire('three-obj-loader')(THREE)\n\nexport var textureLoaded = new Promise((resolve, reject) => {\n (new THREE.TextureLoader()).load(require('./assets/iridescent.bmp'), function(texture) {\n resolve(texture);\n });\n})\n\nexport var objLoaded = new Promise((resolve, reject) => {\n (new THREE.OBJLoader()).load(require('./assets/wahoo.obj'), function(obj) {\n var geo = obj.children[0].geometry;\n geo.computeBoundingSphere();\n resolve(geo);\n });\n})\n\n\n// WEBPACK FOOTER //\n// ./src/iridescentmario.js","const THREE = require('three');\nconst EffectComposer = require('three-effectcomposer')(THREE)\n\nvar options = {\n amount: 1\n}\nvar GaussianShader = new EffectComposer.ShaderPass({\n uniforms: {\n tDiffuse: {\n type: 't',\n value: null\n },\n u_amount: {\n type: 'f',\n value: options.amount\n }, \n sHeight: {\n type: 'f', \n value: screen.height\n }, \n sWidth: {\n type: 'f', \n value: screen.width\n }\n },\n vertexShader: require('../glsl/pass-vert.glsl'),\n fragmentShader: require('../glsl/gaussian-frag.glsl')\n});\n\nexport default function Gaussian(renderer, scene, camera) {\n // this is the THREE.js object for doing post-process effects\n var composer = new EffectComposer(renderer);\n\n // first render the scene normally and add that as the first pass\n composer.addPass(new EffectComposer.RenderPass(scene, camera));\n\n // then take the rendered result and apply the GaussianShader\n composer.addPass(GaussianShader); \n\n // set this to true on the shader for your last pass to write to the screen\n GaussianShader.renderToScreen = true; \n\n return {\n initGUI: function(gui) {\n gui.add(options, 'amount', 0, 1).onChange(function(val) {\n GaussianShader.material.uniforms.u_amount.value = val;\n });\n },\n \n render: function() {;\n composer.render();\n }\n }\n}\n\n\n// WEBPACK FOOTER //\n// ./src/post/gaussian.js","const THREE = require('three');\nconst EffectComposer = require('three-effectcomposer')(THREE)\n\nvar options = {\n amount: 1\n}\n\nvar GrayscaleShader = new EffectComposer.ShaderPass({\n uniforms: {\n tDiffuse: {\n type: 't',\n value: null\n },\n u_amount: {\n type: 'f',\n value: options.amount\n }\n },\n vertexShader: require('../glsl/pass-vert.glsl'),\n fragmentShader: require('../glsl/grayscale-frag.glsl')\n});\n\nexport default function Grayscale(renderer, scene, camera) {\n \n // this is the THREE.js object for doing post-process effects\n var composer = new EffectComposer(renderer);\n\n // first render the scene normally and add that as the first pass\n composer.addPass(new EffectComposer.RenderPass(scene, camera));\n\n // then take the rendered result and apply the GrayscaleShader\n composer.addPass(GrayscaleShader); \n\n // set this to true on the shader for your last pass to write to the screen\n GrayscaleShader.renderToScreen = true; \n\n return {\n initGUI: function(gui) {\n gui.add(options, 'amount', 0, 1).onChange(function(val) {\n GrayscaleShader.material.uniforms.u_amount.value = val;\n });\n },\n \n render: function() {;\n composer.render();\n }\n }\n}\n\n\n// WEBPACK FOOTER //\n// ./src/post/grayscale.js","\n// This file exports available shaders to the GUI.\n\n// don't worry about this one. This is just to apply no filter\nexport function None(renderer, scene, camera) {\n return {\n initGUI: function(gui) {\n\n },\n\n render: function() {\n renderer.render(scene, camera);\n }\n }\n}\n\n// follow this syntax to make your shaders available to the GUI\nexport {default as Grayscale} from './grayscale'\nexport {default as Invert} from './invert'\nexport {default as Sobel} from './sobel'\nexport {default as Vignette} from './vignette'\nexport {default as Gaussian} from './gaussian'\nexport {default as Pointilism} from './pointilism'\n\n\n// WEBPACK FOOTER //\n// ./src/post/index.js","const THREE = require('three');\nconst EffectComposer = require('three-effectcomposer')(THREE)\n\nvar options = {\n amount: 1\n}\nvar t = new Date();\nvar invertShader = new EffectComposer.ShaderPass({\n uniforms: {\n tDiffuse: {\n type: 't',\n value: null\n },\n u_amount: {\n type: 'f',\n value: options.amount\n }, \n time: {\n type: 'f', \n value: t.getTime()\n }\n },\n vertexShader: require('../glsl/pass-vert.glsl'),\n fragmentShader: require('../glsl/invert-frag.glsl')\n});\n\nexport default function invert(renderer, scene, camera) {\n \n // this is the THREE.js object for doing post-process effects\n var composer = new EffectComposer(renderer);\n\n // first render the scene normally and add that as the first pass\n composer.addPass(new EffectComposer.RenderPass(scene, camera));\n\n // then take the rendered result and apply the GrayscaleShader\n composer.addPass(invertShader); \n\n // set this to true on the shader for your last pass to write to the screen\n invertShader.renderToScreen = true; \n\n return {\n initGUI: function(gui) {\n gui.add(options, 'amount', 0, 1).onChange(function(val) {\n invertShader.material.uniforms.u_amount.value = val;\n });\n },\n \n render: function() {;\n composer.render();\n }\n }\n}\n\n\n// WEBPACK FOOTER //\n// ./src/post/invert.js","const THREE = require('three');\nconst EffectComposer = require('three-effectcomposer')(THREE)\n\nvar options = {\n amount: 1\n}\nvar PointilismShader = new EffectComposer.ShaderPass({\n uniforms: {\n tDiffuse: {\n type: 't',\n value: null\n },\n u_amount: {\n type: 'f',\n value: options.amount\n }, \n sHeight: {\n type: 'f', \n value: screen.height\n }, \n sWidth: {\n type: 'f', \n value: screen.width\n }\n },\n vertexShader: require('../glsl/pass-vert.glsl'),\n fragmentShader: require('../glsl/pointilism-frag.glsl')\n});\n\nexport default function Pointilism(renderer, scene, camera) {\n // this is the THREE.js object for doing post-process effects\n var composer = new EffectComposer(renderer);\n\n // first render the scene normally and add that as the first pass\n composer.addPass(new EffectComposer.RenderPass(scene, camera));\n\n // then take the rendered result and apply the PointilismShader\n composer.addPass(PointilismShader); \n\n // set this to true on the shader for your last pass to write to the screen\n PointilismShader.renderToScreen = true; \n\n return {\n initGUI: function(gui) {\n gui.add(options, 'amount', 0, 1).onChange(function(val) {\n PointilismShader.material.uniforms.u_amount.value = val;\n });\n },\n \n render: function() {;\n composer.render();\n }\n }\n}\n\n\n// WEBPACK FOOTER //\n// ./src/post/pointilism.js","const THREE = require('three');\nconst EffectComposer = require('three-effectcomposer')(THREE)\n\nvar options = {\n amount: 1\n}\nvar SobelShader = new EffectComposer.ShaderPass({\n uniforms: {\n tDiffuse: {\n type: 't',\n value: null\n },\n u_amount: {\n type: 'f',\n value: options.amount\n }, \n sHeight: {\n type: 'f', \n value: screen.height\n }, \n sWidth: {\n type: 'f', \n value: screen.width\n }\n },\n vertexShader: require('../glsl/pass-vert.glsl'),\n fragmentShader: require('../glsl/sobel-frag.glsl')\n});\n\nexport default function Grayscale(renderer, scene, camera) {\n // this is the THREE.js object for doing post-process effects\n var composer = new EffectComposer(renderer);\n\n // first render the scene normally and add that as the first pass\n composer.addPass(new EffectComposer.RenderPass(scene, camera));\n\n // then take the rendered result and apply the SobelShader\n composer.addPass(SobelShader); \n\n // set this to true on the shader for your last pass to write to the screen\n SobelShader.renderToScreen = true; \n\n return {\n initGUI: function(gui) {\n gui.add(options, 'amount', 0, 1).onChange(function(val) {\n SobelShader.material.uniforms.u_amount.value = val;\n });\n },\n \n render: function() {;\n composer.render();\n }\n }\n}\n\n\n// WEBPACK FOOTER //\n// ./src/post/sobel.js","const THREE = require('three');\nconst EffectComposer = require('three-effectcomposer')(THREE)\n\nvar options = {\n amount: 1,\n color: '#ffffff'\n}\n\nvar VignetteShaders = new EffectComposer.ShaderPass({\n uniforms: {\n tDiffuse: {\n type: 't',\n value: null\n },\n u_amount: {\n type: 'f',\n value: options.amount\n }, \n u_color: {\n type: 'v3',\n value: new THREE.Color(options.lightColor)\n }\n },\n vertexShader: require('../glsl/pass-vert.glsl'),\n fragmentShader: require('../glsl/vignette-frag.glsl')\n});\n\nexport default function Vignette(renderer, scene, camera) {\n \n // this is the THREE.js object for doing post-process effects\n var composer = new EffectComposer(renderer);\n\n // first render the scene normally and add that as the first pass\n composer.addPass(new EffectComposer.RenderPass(scene, camera));\n\n // then take the rendered result and apply the VignetteShaders\n composer.addPass(VignetteShaders); \n\n // set this to true on the shader for your last pass to write to the screen\n VignetteShaders.renderToScreen = true; \n\n return {\n initGUI: function(gui) {\n gui.add(options, 'amount', 0, 1).onChange(function(val) {\n VignetteShaders.material.uniforms.u_amount.value = val;\n });\n gui.addColor(options, 'color').onChange(function(val) {\n VignetteShaders.material.uniforms.u_color.value = new THREE.Color(val);\n });\n },\n \n render: function() {;\n composer.render();\n }\n }\n}\n\n\n// WEBPACK FOOTER //\n// ./src/post/vignette.js","\n// This file exports available shaders to the GUI.\n// follow this syntax to make your shaders available to the GUI\nexport {default as Lambert} from './lambert'\nexport {default as Toon} from './toon'\nexport {default as Iridescent} from './iridescent'\n\n\n// WEBPACK FOOTER //\n// ./src/shaders/index.js","\nconst THREE = require('three');\nimport {textureLoaded} from '../iridescentmario'\n\n// options for lambert shader\nvar options = {\n lightColor: '#ffffff',\n lightIntensity: 2,\n albedo: '#dddddd',\n ambient: '#111111',\n useTexture: true\n}\n\nexport default function(renderer, scene, camera) {\n const Shader = {\n initGUI: function(gui) {\n gui.addColor(options, 'lightColor').onChange(function(val) {\n Shader.material.uniforms.u_lightCol.value = new THREE.Color(val);\n });\n gui.add(options, 'lightIntensity').onChange(function(val) {\n Shader.material.uniforms.u_lightIntensity.value = val;\n });\n gui.addColor(options, 'albedo').onChange(function(val) {\n Shader.material.uniforms.u_albedo.value = new THREE.Color(val);\n });\n gui.addColor(options, 'ambient').onChange(function(val) {\n Shader.material.uniforms.u_ambient.value = new THREE.Color(val);\n });\n gui.add(options, 'useTexture').onChange(function(val) {\n Shader.material.uniforms.u_useTexture.value = val;\n });\n },\n \n material: new THREE.ShaderMaterial({\n uniforms: {\n texture: {\n type: \"t\", \n value: null\n },\n u_useTexture: {\n type: 'i',\n value: options.useTexture\n },\n u_albedo: {\n type: 'v3',\n value: new THREE.Color(options.albedo)\n },\n u_ambient: {\n type: 'v3',\n value: new THREE.Color(options.ambient)\n },\n u_lightPos: {\n type: 'v3',\n value: new THREE.Vector3(30, 50, 40)\n },\n u_lightCol: {\n type: 'v3',\n value: new THREE.Color(options.lightColor)\n },\n u_lightIntensity: {\n type: 'f',\n value: options.lightIntensity\n },\n u_camPos: {\n type: 'v3',\n value: camera.position\n }\n },\n vertexShader: require('../glsl/iridescent-vert.glsl'),\n fragmentShader: require('../glsl/iridescent-frag.glsl')\n })\n }\n\n // once the Mario texture loads, bind it to the material\n textureLoaded.then(function(texture) {\n Shader.material.uniforms.texture.value = texture;\n });\n\n return Shader;\n}\n\n\n// WEBPACK FOOTER //\n// ./src/shaders/iridescent.js","\nconst THREE = require('three');\nimport {textureLoaded} from '../mario'\n\n// options for lambert shader\nvar options = {\n lightColor: '#ffffff',\n lightIntensity: 2,\n albedo: '#dddddd',\n ambient: '#111111',\n useTexture: true\n}\n\nexport default function(renderer, scene, camera) {\n \n const Shader = {\n initGUI: function(gui) {\n gui.addColor(options, 'lightColor').onChange(function(val) {\n Shader.material.uniforms.u_lightCol.value = new THREE.Color(val);\n });\n gui.add(options, 'lightIntensity').onChange(function(val) {\n Shader.material.uniforms.u_lightIntensity.value = val;\n });\n gui.addColor(options, 'albedo').onChange(function(val) {\n Shader.material.uniforms.u_albedo.value = new THREE.Color(val);\n });\n gui.addColor(options, 'ambient').onChange(function(val) {\n Shader.material.uniforms.u_ambient.value = new THREE.Color(val);\n });\n gui.add(options, 'useTexture').onChange(function(val) {\n Shader.material.uniforms.u_useTexture.value = val;\n });\n },\n \n material: new THREE.ShaderMaterial({\n uniforms: {\n texture: {\n type: \"t\", \n value: null\n },\n u_useTexture: {\n type: 'i',\n value: options.useTexture\n },\n u_albedo: {\n type: 'v3',\n value: new THREE.Color(options.albedo)\n },\n u_ambient: {\n type: 'v3',\n value: new THREE.Color(options.ambient)\n },\n u_lightPos: {\n type: 'v3',\n value: new THREE.Vector3(30, 50, 40)\n },\n u_lightCol: {\n type: 'v3',\n value: new THREE.Color(options.lightColor)\n },\n u_lightIntensity: {\n type: 'f',\n value: options.lightIntensity\n }\n },\n vertexShader: require('../glsl/lambert-vert.glsl'),\n fragmentShader: require('../glsl/lambert-frag.glsl')\n })\n }\n\n // once the Mario texture loads, bind it to the material\n textureLoaded.then(function(texture) {\n Shader.material.uniforms.texture.value = texture;\n });\n\n return Shader;\n}\n\n\n// WEBPACK FOOTER //\n// ./src/shaders/lambert.js","\nconst THREE = require('three');\nimport {textureLoaded} from '../mario'\n\n// options for lambert shader\nvar options = {\n lightColor: '#ffffff',\n lightIntensity: 2,\n albedo: '#dddddd',\n ambient: '#111111',\n useTexture: true\n}\n\nexport default function(renderer, scene, camera) {\n var pLocal = new THREE.Vector3(0, 0, -1);\n var pWorld = pLocal.applyMatrix4( camera.matrixWorld );\n var dir = pWorld.sub( camera.position ).normalize();\n const Shader = {\n initGUI: function(gui) {\n gui.addColor(options, 'lightColor').onChange(function(val) {\n Shader.material.uniforms.u_lightCol.value = new THREE.Color(val);\n });\n gui.add(options, 'lightIntensity').onChange(function(val) {\n Shader.material.uniforms.u_lightIntensity.value = val;\n });\n gui.addColor(options, 'albedo').onChange(function(val) {\n Shader.material.uniforms.u_albedo.value = new THREE.Color(val);\n });\n gui.addColor(options, 'ambient').onChange(function(val) {\n Shader.material.uniforms.u_ambient.value = new THREE.Color(val);\n });\n gui.add(options, 'useTexture').onChange(function(val) {\n Shader.material.uniforms.u_useTexture.value = val;\n });\n },\n \n material: new THREE.ShaderMaterial({\n uniforms: {\n texture: {\n type: \"t\", \n value: null\n },\n u_useTexture: {\n type: 'i',\n value: options.useTexture\n },\n u_albedo: {\n type: 'v3',\n value: new THREE.Color(options.albedo)\n },\n u_ambient: {\n type: 'v3',\n value: new THREE.Color(options.ambient)\n },\n u_lightPos: {\n type: 'v3',\n value: new THREE.Vector3(30, 50, 40)\n },\n u_lightCol: {\n type: 'v3',\n value: new THREE.Color(options.lightColor)\n },\n u_lightIntensity: {\n type: 'f',\n value: options.lightIntensity\n },\n u_camPos: {\n type: 'v3',\n value: camera.position\n }, \n u_camDir: {\n type: 'v3', \n value: dir\n }\n },\n vertexShader: require('../glsl/toon-vert.glsl'),\n fragmentShader: require('../glsl/toon-frag.glsl')\n })\n }\n\n // once the Mario texture loads, bind it to the material\n textureLoaded.then(function(texture) {\n Shader.material.uniforms.texture.value = texture;\n });\n\n return Shader;\n}\n\n\n// WEBPACK FOOTER //\n// ./src/shaders/toon.js","module.exports = require('./vendor/dat.gui')\nmodule.exports.color = require('./vendor/dat.color')\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/dat-gui/index.js\n// module id = 22\n// module chunks = 0","/**\n * dat-gui JavaScript Controller Library\n * http://code.google.com/p/dat-gui\n *\n * Copyright 2011 Data Arts Team, Google Creative Lab\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n */\n\n/** @namespace */\nvar dat = module.exports = dat || {};\n\n/** @namespace */\ndat.color = dat.color || {};\n\n/** @namespace */\ndat.utils = dat.utils || {};\n\ndat.utils.common = (function () {\n \n var ARR_EACH = Array.prototype.forEach;\n var ARR_SLICE = Array.prototype.slice;\n\n /**\n * Band-aid methods for things that should be a lot easier in JavaScript.\n * Implementation and structure inspired by underscore.js\n * http://documentcloud.github.com/underscore/\n */\n\n return { \n \n BREAK: {},\n \n extend: function(target) {\n \n this.each(ARR_SLICE.call(arguments, 1), function(obj) {\n \n for (var key in obj)\n if (!this.isUndefined(obj[key])) \n target[key] = obj[key];\n \n }, this);\n \n return target;\n \n },\n \n defaults: function(target) {\n \n this.each(ARR_SLICE.call(arguments, 1), function(obj) {\n \n for (var key in obj)\n if (this.isUndefined(target[key])) \n target[key] = obj[key];\n \n }, this);\n \n return target;\n \n },\n \n compose: function() {\n var toCall = ARR_SLICE.call(arguments);\n return function() {\n var args = ARR_SLICE.call(arguments);\n for (var i = toCall.length -1; i >= 0; i--) {\n args = [toCall[i].apply(this, args)];\n }\n return args[0];\n }\n },\n \n each: function(obj, itr, scope) {\n\n \n if (ARR_EACH && obj.forEach === ARR_EACH) { \n \n obj.forEach(itr, scope);\n \n } else if (obj.length === obj.length + 0) { // Is number but not NaN\n \n for (var key = 0, l = obj.length; key < l; key++)\n if (key in obj && itr.call(scope, obj[key], key) === this.BREAK) \n return;\n \n } else {\n\n for (var key in obj) \n if (itr.call(scope, obj[key], key) === this.BREAK)\n return;\n \n }\n \n },\n \n defer: function(fnc) {\n setTimeout(fnc, 0);\n },\n \n toArray: function(obj) {\n if (obj.toArray) return obj.toArray();\n return ARR_SLICE.call(obj);\n },\n\n isUndefined: function(obj) {\n return obj === undefined;\n },\n \n isNull: function(obj) {\n return obj === null;\n },\n \n isNaN: function(obj) {\n return obj !== obj;\n },\n \n isArray: Array.isArray || function(obj) {\n return obj.constructor === Array;\n },\n \n isObject: function(obj) {\n return obj === Object(obj);\n },\n \n isNumber: function(obj) {\n return obj === obj+0;\n },\n \n isString: function(obj) {\n return obj === obj+'';\n },\n \n isBoolean: function(obj) {\n return obj === false || obj === true;\n },\n \n isFunction: function(obj) {\n return Object.prototype.toString.call(obj) === '[object Function]';\n }\n \n };\n \n})();\n\n\ndat.color.toString = (function (common) {\n\n return function(color) {\n\n if (color.a == 1 || common.isUndefined(color.a)) {\n\n var s = color.hex.toString(16);\n while (s.length < 6) {\n s = '0' + s;\n }\n\n return '#' + s;\n\n } else {\n\n return 'rgba(' + Math.round(color.r) + ',' + Math.round(color.g) + ',' + Math.round(color.b) + ',' + color.a + ')';\n\n }\n\n }\n\n})(dat.utils.common);\n\n\ndat.Color = dat.color.Color = (function (interpret, math, toString, common) {\n\n var Color = function() {\n\n this.__state = interpret.apply(this, arguments);\n\n if (this.__state === false) {\n throw 'Failed to interpret color arguments';\n }\n\n this.__state.a = this.__state.a || 1;\n\n\n };\n\n Color.COMPONENTS = ['r','g','b','h','s','v','hex','a'];\n\n common.extend(Color.prototype, {\n\n toString: function() {\n return toString(this);\n },\n\n toOriginal: function() {\n return this.__state.conversion.write(this);\n }\n\n });\n\n defineRGBComponent(Color.prototype, 'r', 2);\n defineRGBComponent(Color.prototype, 'g', 1);\n defineRGBComponent(Color.prototype, 'b', 0);\n\n defineHSVComponent(Color.prototype, 'h');\n defineHSVComponent(Color.prototype, 's');\n defineHSVComponent(Color.prototype, 'v');\n\n Object.defineProperty(Color.prototype, 'a', {\n\n get: function() {\n return this.__state.a;\n },\n\n set: function(v) {\n this.__state.a = v;\n }\n\n });\n\n Object.defineProperty(Color.prototype, 'hex', {\n\n get: function() {\n\n if (!this.__state.space !== 'HEX') {\n this.__state.hex = math.rgb_to_hex(this.r, this.g, this.b);\n }\n\n return this.__state.hex;\n\n },\n\n set: function(v) {\n\n this.__state.space = 'HEX';\n this.__state.hex = v;\n\n }\n\n });\n\n function defineRGBComponent(target, component, componentHexIndex) {\n\n Object.defineProperty(target, component, {\n\n get: function() {\n\n if (this.__state.space === 'RGB') {\n return this.__state[component];\n }\n\n recalculateRGB(this, component, componentHexIndex);\n\n return this.__state[component];\n\n },\n\n set: function(v) {\n\n if (this.__state.space !== 'RGB') {\n recalculateRGB(this, component, componentHexIndex);\n this.__state.space = 'RGB';\n }\n\n this.__state[component] = v;\n\n }\n\n });\n\n }\n\n function defineHSVComponent(target, component) {\n\n Object.defineProperty(target, component, {\n\n get: function() {\n\n if (this.__state.space === 'HSV')\n return this.__state[component];\n\n recalculateHSV(this);\n\n return this.__state[component];\n\n },\n\n set: function(v) {\n\n if (this.__state.space !== 'HSV') {\n recalculateHSV(this);\n this.__state.space = 'HSV';\n }\n\n this.__state[component] = v;\n\n }\n\n });\n\n }\n\n function recalculateRGB(color, component, componentHexIndex) {\n\n if (color.__state.space === 'HEX') {\n\n color.__state[component] = math.component_from_hex(color.__state.hex, componentHexIndex);\n\n } else if (color.__state.space === 'HSV') {\n\n common.extend(color.__state, math.hsv_to_rgb(color.__state.h, color.__state.s, color.__state.v));\n\n } else {\n\n throw 'Corrupted color state';\n\n }\n\n }\n\n function recalculateHSV(color) {\n\n var result = math.rgb_to_hsv(color.r, color.g, color.b);\n\n common.extend(color.__state,\n {\n s: result.s,\n v: result.v\n }\n );\n\n if (!common.isNaN(result.h)) {\n color.__state.h = result.h;\n } else if (common.isUndefined(color.__state.h)) {\n color.__state.h = 0;\n }\n\n }\n\n return Color;\n\n})(dat.color.interpret = (function (toString, common) {\n\n var result, toReturn;\n\n var interpret = function() {\n\n toReturn = false;\n\n var original = arguments.length > 1 ? common.toArray(arguments) : arguments[0];\n\n common.each(INTERPRETATIONS, function(family) {\n\n if (family.litmus(original)) {\n\n common.each(family.conversions, function(conversion, conversionName) {\n\n result = conversion.read(original);\n\n if (toReturn === false && result !== false) {\n toReturn = result;\n result.conversionName = conversionName;\n result.conversion = conversion;\n return common.BREAK;\n\n }\n\n });\n\n return common.BREAK;\n\n }\n\n });\n\n return toReturn;\n\n };\n\n var INTERPRETATIONS = [\n\n // Strings\n {\n\n litmus: common.isString,\n\n conversions: {\n\n THREE_CHAR_HEX: {\n\n read: function(original) {\n\n var test = original.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);\n if (test === null) return false;\n\n return {\n space: 'HEX',\n hex: parseInt(\n '0x' +\n test[1].toString() + test[1].toString() +\n test[2].toString() + test[2].toString() +\n test[3].toString() + test[3].toString())\n };\n\n },\n\n write: toString\n\n },\n\n SIX_CHAR_HEX: {\n\n read: function(original) {\n\n var test = original.match(/^#([A-F0-9]{6})$/i);\n if (test === null) return false;\n\n return {\n space: 'HEX',\n hex: parseInt('0x' + test[1].toString())\n };\n\n },\n\n write: toString\n\n },\n\n CSS_RGB: {\n\n read: function(original) {\n\n var test = original.match(/^rgb\\(\\s*(.+)\\s*,\\s*(.+)\\s*,\\s*(.+)\\s*\\)/);\n if (test === null) return false;\n\n return {\n space: 'RGB',\n r: parseFloat(test[1]),\n g: parseFloat(test[2]),\n b: parseFloat(test[3])\n };\n\n },\n\n write: toString\n\n },\n\n CSS_RGBA: {\n\n read: function(original) {\n\n var test = original.match(/^rgba\\(\\s*(.+)\\s*,\\s*(.+)\\s*,\\s*(.+)\\s*\\,\\s*(.+)\\s*\\)/);\n if (test === null) return false;\n\n return {\n space: 'RGB',\n r: parseFloat(test[1]),\n g: parseFloat(test[2]),\n b: parseFloat(test[3]),\n a: parseFloat(test[4])\n };\n\n },\n\n write: toString\n\n }\n\n }\n\n },\n\n // Numbers\n {\n\n litmus: common.isNumber,\n\n conversions: {\n\n HEX: {\n read: function(original) {\n return {\n space: 'HEX',\n hex: original,\n conversionName: 'HEX'\n }\n },\n\n write: function(color) {\n return color.hex;\n }\n }\n\n }\n\n },\n\n // Arrays\n {\n\n litmus: common.isArray,\n\n conversions: {\n\n RGB_ARRAY: {\n read: function(original) {\n if (original.length != 3) return false;\n return {\n space: 'RGB',\n r: original[0],\n g: original[1],\n b: original[2]\n };\n },\n\n write: function(color) {\n return [color.r, color.g, color.b];\n }\n\n },\n\n RGBA_ARRAY: {\n read: function(original) {\n if (original.length != 4) return false;\n return {\n space: 'RGB',\n r: original[0],\n g: original[1],\n b: original[2],\n a: original[3]\n };\n },\n\n write: function(color) {\n return [color.r, color.g, color.b, color.a];\n }\n\n }\n\n }\n\n },\n\n // Objects\n {\n\n litmus: common.isObject,\n\n conversions: {\n\n RGBA_OBJ: {\n read: function(original) {\n if (common.isNumber(original.r) &&\n common.isNumber(original.g) &&\n common.isNumber(original.b) &&\n common.isNumber(original.a)) {\n return {\n space: 'RGB',\n r: original.r,\n g: original.g,\n b: original.b,\n a: original.a\n }\n }\n return false;\n },\n\n write: function(color) {\n return {\n r: color.r,\n g: color.g,\n b: color.b,\n a: color.a\n }\n }\n },\n\n RGB_OBJ: {\n read: function(original) {\n if (common.isNumber(original.r) &&\n common.isNumber(original.g) &&\n common.isNumber(original.b)) {\n return {\n space: 'RGB',\n r: original.r,\n g: original.g,\n b: original.b\n }\n }\n return false;\n },\n\n write: function(color) {\n return {\n r: color.r,\n g: color.g,\n b: color.b\n }\n }\n },\n\n HSVA_OBJ: {\n read: function(original) {\n if (common.isNumber(original.h) &&\n common.isNumber(original.s) &&\n common.isNumber(original.v) &&\n common.isNumber(original.a)) {\n return {\n space: 'HSV',\n h: original.h,\n s: original.s,\n v: original.v,\n a: original.a\n }\n }\n return false;\n },\n\n write: function(color) {\n return {\n h: color.h,\n s: color.s,\n v: color.v,\n a: color.a\n }\n }\n },\n\n HSV_OBJ: {\n read: function(original) {\n if (common.isNumber(original.h) &&\n common.isNumber(original.s) &&\n common.isNumber(original.v)) {\n return {\n space: 'HSV',\n h: original.h,\n s: original.s,\n v: original.v\n }\n }\n return false;\n },\n\n write: function(color) {\n return {\n h: color.h,\n s: color.s,\n v: color.v\n }\n }\n\n }\n\n }\n\n }\n\n\n ];\n\n return interpret;\n\n\n})(dat.color.toString,\ndat.utils.common),\ndat.color.math = (function () {\n\n var tmpComponent;\n\n return {\n\n hsv_to_rgb: function(h, s, v) {\n\n var hi = Math.floor(h / 60) % 6;\n\n var f = h / 60 - Math.floor(h / 60);\n var p = v * (1.0 - s);\n var q = v * (1.0 - (f * s));\n var t = v * (1.0 - ((1.0 - f) * s));\n var c = [\n [v, t, p],\n [q, v, p],\n [p, v, t],\n [p, q, v],\n [t, p, v],\n [v, p, q]\n ][hi];\n\n return {\n r: c[0] * 255,\n g: c[1] * 255,\n b: c[2] * 255\n };\n\n },\n\n rgb_to_hsv: function(r, g, b) {\n\n var min = Math.min(r, g, b),\n max = Math.max(r, g, b),\n delta = max - min,\n h, s;\n\n if (max != 0) {\n s = delta / max;\n } else {\n return {\n h: NaN,\n s: 0,\n v: 0\n };\n }\n\n if (r == max) {\n h = (g - b) / delta;\n } else if (g == max) {\n h = 2 + (b - r) / delta;\n } else {\n h = 4 + (r - g) / delta;\n }\n h /= 6;\n if (h < 0) {\n h += 1;\n }\n\n return {\n h: h * 360,\n s: s,\n v: max / 255\n };\n },\n\n rgb_to_hex: function(r, g, b) {\n var hex = this.hex_with_component(0, 2, r);\n hex = this.hex_with_component(hex, 1, g);\n hex = this.hex_with_component(hex, 0, b);\n return hex;\n },\n\n component_from_hex: function(hex, componentIndex) {\n return (hex >> (componentIndex * 8)) & 0xFF;\n },\n\n hex_with_component: function(hex, componentIndex, value) {\n return value << (tmpComponent = componentIndex * 8) | (hex & ~ (0xFF << tmpComponent));\n }\n\n }\n\n})(),\ndat.color.toString,\ndat.utils.common);\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/dat-gui/vendor/dat.color.js\n// module id = 23\n// module chunks = 0","/**\n * dat-gui JavaScript Controller Library\n * http://code.google.com/p/dat-gui\n *\n * Copyright 2011 Data Arts Team, Google Creative Lab\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n */\n\n/** @namespace */\nvar dat = module.exports = dat || {};\n\n/** @namespace */\ndat.gui = dat.gui || {};\n\n/** @namespace */\ndat.utils = dat.utils || {};\n\n/** @namespace */\ndat.controllers = dat.controllers || {};\n\n/** @namespace */\ndat.dom = dat.dom || {};\n\n/** @namespace */\ndat.color = dat.color || {};\n\ndat.utils.css = (function () {\n return {\n load: function (url, doc) {\n doc = doc || document;\n var link = doc.createElement('link');\n link.type = 'text/css';\n link.rel = 'stylesheet';\n link.href = url;\n doc.getElementsByTagName('head')[0].appendChild(link);\n },\n inject: function(css, doc) {\n doc = doc || document;\n var injected = document.createElement('style');\n injected.type = 'text/css';\n injected.innerHTML = css;\n doc.getElementsByTagName('head')[0].appendChild(injected);\n }\n }\n})();\n\n\ndat.utils.common = (function () {\n \n var ARR_EACH = Array.prototype.forEach;\n var ARR_SLICE = Array.prototype.slice;\n\n /**\n * Band-aid methods for things that should be a lot easier in JavaScript.\n * Implementation and structure inspired by underscore.js\n * http://documentcloud.github.com/underscore/\n */\n\n return { \n \n BREAK: {},\n \n extend: function(target) {\n \n this.each(ARR_SLICE.call(arguments, 1), function(obj) {\n \n for (var key in obj)\n if (!this.isUndefined(obj[key])) \n target[key] = obj[key];\n \n }, this);\n \n return target;\n \n },\n \n defaults: function(target) {\n \n this.each(ARR_SLICE.call(arguments, 1), function(obj) {\n \n for (var key in obj)\n if (this.isUndefined(target[key])) \n target[key] = obj[key];\n \n }, this);\n \n return target;\n \n },\n \n compose: function() {\n var toCall = ARR_SLICE.call(arguments);\n return function() {\n var args = ARR_SLICE.call(arguments);\n for (var i = toCall.length -1; i >= 0; i--) {\n args = [toCall[i].apply(this, args)];\n }\n return args[0];\n }\n },\n \n each: function(obj, itr, scope) {\n\n \n if (ARR_EACH && obj.forEach === ARR_EACH) { \n \n obj.forEach(itr, scope);\n \n } else if (obj.length === obj.length + 0) { // Is number but not NaN\n \n for (var key = 0, l = obj.length; key < l; key++)\n if (key in obj && itr.call(scope, obj[key], key) === this.BREAK) \n return;\n \n } else {\n\n for (var key in obj) \n if (itr.call(scope, obj[key], key) === this.BREAK)\n return;\n \n }\n \n },\n \n defer: function(fnc) {\n setTimeout(fnc, 0);\n },\n \n toArray: function(obj) {\n if (obj.toArray) return obj.toArray();\n return ARR_SLICE.call(obj);\n },\n\n isUndefined: function(obj) {\n return obj === undefined;\n },\n \n isNull: function(obj) {\n return obj === null;\n },\n \n isNaN: function(obj) {\n return obj !== obj;\n },\n \n isArray: Array.isArray || function(obj) {\n return obj.constructor === Array;\n },\n \n isObject: function(obj) {\n return obj === Object(obj);\n },\n \n isNumber: function(obj) {\n return obj === obj+0;\n },\n \n isString: function(obj) {\n return obj === obj+'';\n },\n \n isBoolean: function(obj) {\n return obj === false || obj === true;\n },\n \n isFunction: function(obj) {\n return Object.prototype.toString.call(obj) === '[object Function]';\n }\n \n };\n \n})();\n\n\ndat.controllers.Controller = (function (common) {\n\n /**\n * @class An \"abstract\" class that represents a given property of an object.\n *\n * @param {Object} object The object to be manipulated\n * @param {string} property The name of the property to be manipulated\n *\n * @member dat.controllers\n */\n var Controller = function(object, property) {\n\n this.initialValue = object[property];\n\n /**\n * Those who extend this class will put their DOM elements in here.\n * @type {DOMElement}\n */\n this.domElement = document.createElement('div');\n\n /**\n * The object to manipulate\n * @type {Object}\n */\n this.object = object;\n\n /**\n * The name of the property to manipulate\n * @type {String}\n */\n this.property = property;\n\n /**\n * The function to be called on change.\n * @type {Function}\n * @ignore\n */\n this.__onChange = undefined;\n\n /**\n * The function to be called on finishing change.\n * @type {Function}\n * @ignore\n */\n this.__onFinishChange = undefined;\n\n };\n\n common.extend(\n\n Controller.prototype,\n\n /** @lends dat.controllers.Controller.prototype */\n {\n\n /**\n * Specify that a function fire every time someone changes the value with\n * this Controller.\n *\n * @param {Function} fnc This function will be called whenever the value\n * is modified via this Controller.\n * @returns {dat.controllers.Controller} this\n */\n onChange: function(fnc) {\n this.__onChange = fnc;\n return this;\n },\n\n /**\n * Specify that a function fire every time someone \"finishes\" changing\n * the value wih this Controller. Useful for values that change\n * incrementally like numbers or strings.\n *\n * @param {Function} fnc This function will be called whenever\n * someone \"finishes\" changing the value via this Controller.\n * @returns {dat.controllers.Controller} this\n */\n onFinishChange: function(fnc) {\n this.__onFinishChange = fnc;\n return this;\n },\n\n /**\n * Change the value of object[property]\n *\n * @param {Object} newValue The new value of object[property]\n */\n setValue: function(newValue) {\n this.object[this.property] = newValue;\n if (this.__onChange) {\n this.__onChange.call(this, newValue);\n }\n this.updateDisplay();\n return this;\n },\n\n /**\n * Gets the value of object[property]\n *\n * @returns {Object} The current value of object[property]\n */\n getValue: function() {\n return this.object[this.property];\n },\n\n /**\n * Refreshes the visual display of a Controller in order to keep sync\n * with the object's current value.\n * @returns {dat.controllers.Controller} this\n */\n updateDisplay: function() {\n return this;\n },\n\n /**\n * @returns {Boolean} true if the value has deviated from initialValue\n */\n isModified: function() {\n return this.initialValue !== this.getValue()\n }\n\n }\n\n );\n\n return Controller;\n\n\n})(dat.utils.common);\n\n\ndat.dom.dom = (function (common) {\n\n var EVENT_MAP = {\n 'HTMLEvents': ['change'],\n 'MouseEvents': ['click','mousemove','mousedown','mouseup', 'mouseover'],\n 'KeyboardEvents': ['keydown']\n };\n\n var EVENT_MAP_INV = {};\n common.each(EVENT_MAP, function(v, k) {\n common.each(v, function(e) {\n EVENT_MAP_INV[e] = k;\n });\n });\n\n var CSS_VALUE_PIXELS = /(\\d+(\\.\\d+)?)px/;\n\n function cssValueToPixels(val) {\n\n if (val === '0' || common.isUndefined(val)) return 0;\n\n var match = val.match(CSS_VALUE_PIXELS);\n\n if (!common.isNull(match)) {\n return parseFloat(match[1]);\n }\n\n // TODO ...ems? %?\n\n return 0;\n\n }\n\n /**\n * @namespace\n * @member dat.dom\n */\n var dom = {\n\n /**\n * \n * @param elem\n * @param selectable\n */\n makeSelectable: function(elem, selectable) {\n\n if (elem === undefined || elem.style === undefined) return;\n\n elem.onselectstart = selectable ? function() {\n return false;\n } : function() {\n };\n\n elem.style.MozUserSelect = selectable ? 'auto' : 'none';\n elem.style.KhtmlUserSelect = selectable ? 'auto' : 'none';\n elem.unselectable = selectable ? 'on' : 'off';\n\n },\n\n /**\n *\n * @param elem\n * @param horizontal\n * @param vertical\n */\n makeFullscreen: function(elem, horizontal, vertical) {\n\n if (common.isUndefined(horizontal)) horizontal = true;\n if (common.isUndefined(vertical)) vertical = true;\n\n elem.style.position = 'absolute';\n\n if (horizontal) {\n elem.style.left = 0;\n elem.style.right = 0;\n }\n if (vertical) {\n elem.style.top = 0;\n elem.style.bottom = 0;\n }\n\n },\n\n /**\n *\n * @param elem\n * @param eventType\n * @param params\n */\n fakeEvent: function(elem, eventType, params, aux) {\n params = params || {};\n var className = EVENT_MAP_INV[eventType];\n if (!className) {\n throw new Error('Event type ' + eventType + ' not supported.');\n }\n var evt = document.createEvent(className);\n switch (className) {\n case 'MouseEvents':\n var clientX = params.x || params.clientX || 0;\n var clientY = params.y || params.clientY || 0;\n evt.initMouseEvent(eventType, params.bubbles || false,\n params.cancelable || true, window, params.clickCount || 1,\n 0, //screen X\n 0, //screen Y\n clientX, //client X\n clientY, //client Y\n false, false, false, false, 0, null);\n break;\n case 'KeyboardEvents':\n var init = evt.initKeyboardEvent || evt.initKeyEvent; // webkit || moz\n common.defaults(params, {\n cancelable: true,\n ctrlKey: false,\n altKey: false,\n shiftKey: false,\n metaKey: false,\n keyCode: undefined,\n charCode: undefined\n });\n init(eventType, params.bubbles || false,\n params.cancelable, window,\n params.ctrlKey, params.altKey,\n params.shiftKey, params.metaKey,\n params.keyCode, params.charCode);\n break;\n default:\n evt.initEvent(eventType, params.bubbles || false,\n params.cancelable || true);\n break;\n }\n common.defaults(evt, aux);\n elem.dispatchEvent(evt);\n },\n\n /**\n *\n * @param elem\n * @param event\n * @param func\n * @param bool\n */\n bind: function(elem, event, func, bool) {\n bool = bool || false;\n if (elem.addEventListener)\n elem.addEventListener(event, func, bool);\n else if (elem.attachEvent)\n elem.attachEvent('on' + event, func);\n return dom;\n },\n\n /**\n *\n * @param elem\n * @param event\n * @param func\n * @param bool\n */\n unbind: function(elem, event, func, bool) {\n bool = bool || false;\n if (elem.removeEventListener)\n elem.removeEventListener(event, func, bool);\n else if (elem.detachEvent)\n elem.detachEvent('on' + event, func);\n return dom;\n },\n\n /**\n *\n * @param elem\n * @param className\n */\n addClass: function(elem, className) {\n if (elem.className === undefined) {\n elem.className = className;\n } else if (elem.className !== className) {\n var classes = elem.className.split(/ +/);\n if (classes.indexOf(className) == -1) {\n classes.push(className);\n elem.className = classes.join(' ').replace(/^\\s+/, '').replace(/\\s+$/, '');\n }\n }\n return dom;\n },\n\n /**\n *\n * @param elem\n * @param className\n */\n removeClass: function(elem, className) {\n if (className) {\n if (elem.className === undefined) {\n // elem.className = className;\n } else if (elem.className === className) {\n elem.removeAttribute('class');\n } else {\n var classes = elem.className.split(/ +/);\n var index = classes.indexOf(className);\n if (index != -1) {\n classes.splice(index, 1);\n elem.className = classes.join(' ');\n }\n }\n } else {\n elem.className = undefined;\n }\n return dom;\n },\n\n hasClass: function(elem, className) {\n return new RegExp('(?:^|\\\\s+)' + className + '(?:\\\\s+|$)').test(elem.className) || false;\n },\n\n /**\n *\n * @param elem\n */\n getWidth: function(elem) {\n\n var style = getComputedStyle(elem);\n\n return cssValueToPixels(style['border-left-width']) +\n cssValueToPixels(style['border-right-width']) +\n cssValueToPixels(style['padding-left']) +\n cssValueToPixels(style['padding-right']) +\n cssValueToPixels(style['width']);\n },\n\n /**\n *\n * @param elem\n */\n getHeight: function(elem) {\n\n var style = getComputedStyle(elem);\n\n return cssValueToPixels(style['border-top-width']) +\n cssValueToPixels(style['border-bottom-width']) +\n cssValueToPixels(style['padding-top']) +\n cssValueToPixels(style['padding-bottom']) +\n cssValueToPixels(style['height']);\n },\n\n /**\n *\n * @param elem\n */\n getOffset: function(elem) {\n var offset = {left: 0, top:0};\n if (elem.offsetParent) {\n do {\n offset.left += elem.offsetLeft;\n offset.top += elem.offsetTop;\n } while (elem = elem.offsetParent);\n }\n return offset;\n },\n\n // http://stackoverflow.com/posts/2684561/revisions\n /**\n * \n * @param elem\n */\n isActive: function(elem) {\n return elem === document.activeElement && ( elem.type || elem.href );\n }\n\n };\n\n return dom;\n\n})(dat.utils.common);\n\n\ndat.controllers.OptionController = (function (Controller, dom, common) {\n\n /**\n * @class Provides a select input to alter the property of an object, using a\n * list of accepted values.\n *\n * @extends dat.controllers.Controller\n *\n * @param {Object} object The object to be manipulated\n * @param {string} property The name of the property to be manipulated\n * @param {Object|string[]} options A map of labels to acceptable values, or\n * a list of acceptable string values.\n *\n * @member dat.controllers\n */\n var OptionController = function(object, property, options) {\n\n OptionController.superclass.call(this, object, property);\n\n var _this = this;\n\n /**\n * The drop down menu\n * @ignore\n */\n this.__select = document.createElement('select');\n\n if (common.isArray(options)) {\n var map = {};\n common.each(options, function(element) {\n map[element] = element;\n });\n options = map;\n }\n\n common.each(options, function(value, key) {\n\n var opt = document.createElement('option');\n opt.innerHTML = key;\n opt.setAttribute('value', value);\n _this.__select.appendChild(opt);\n\n });\n\n // Acknowledge original value\n this.updateDisplay();\n\n dom.bind(this.__select, 'change', function() {\n var desiredValue = this.options[this.selectedIndex].value;\n _this.setValue(desiredValue);\n });\n\n this.domElement.appendChild(this.__select);\n\n };\n\n OptionController.superclass = Controller;\n\n common.extend(\n\n OptionController.prototype,\n Controller.prototype,\n\n {\n\n setValue: function(v) {\n var toReturn = OptionController.superclass.prototype.setValue.call(this, v);\n if (this.__onFinishChange) {\n this.__onFinishChange.call(this, this.getValue());\n }\n return toReturn;\n },\n\n updateDisplay: function() {\n this.__select.value = this.getValue();\n return OptionController.superclass.prototype.updateDisplay.call(this);\n }\n\n }\n\n );\n\n return OptionController;\n\n})(dat.controllers.Controller,\ndat.dom.dom,\ndat.utils.common);\n\n\ndat.controllers.NumberController = (function (Controller, common) {\n\n /**\n * @class Represents a given property of an object that is a number.\n *\n * @extends dat.controllers.Controller\n *\n * @param {Object} object The object to be manipulated\n * @param {string} property The name of the property to be manipulated\n * @param {Object} [params] Optional parameters\n * @param {Number} [params.min] Minimum allowed value\n * @param {Number} [params.max] Maximum allowed value\n * @param {Number} [params.step] Increment by which to change value\n *\n * @member dat.controllers\n */\n var NumberController = function(object, property, params) {\n\n NumberController.superclass.call(this, object, property);\n\n params = params || {};\n\n this.__min = params.min;\n this.__max = params.max;\n this.__step = params.step;\n\n if (common.isUndefined(this.__step)) {\n\n if (this.initialValue == 0) {\n this.__impliedStep = 1; // What are we, psychics?\n } else {\n // Hey Doug, check this out.\n this.__impliedStep = Math.pow(10, Math.floor(Math.log(this.initialValue)/Math.LN10))/10;\n }\n\n } else {\n\n this.__impliedStep = this.__step;\n\n }\n\n this.__precision = numDecimals(this.__impliedStep);\n\n\n };\n\n NumberController.superclass = Controller;\n\n common.extend(\n\n NumberController.prototype,\n Controller.prototype,\n\n /** @lends dat.controllers.NumberController.prototype */\n {\n\n setValue: function(v) {\n\n if (this.__min !== undefined && v < this.__min) {\n v = this.__min;\n } else if (this.__max !== undefined && v > this.__max) {\n v = this.__max;\n }\n\n if (this.__step !== undefined && v % this.__step != 0) {\n v = Math.round(v / this.__step) * this.__step;\n }\n\n return NumberController.superclass.prototype.setValue.call(this, v);\n\n },\n\n /**\n * Specify a minimum value for object[property].\n *\n * @param {Number} minValue The minimum value for\n * object[property]\n * @returns {dat.controllers.NumberController} this\n */\n min: function(v) {\n this.__min = v;\n return this;\n },\n\n /**\n * Specify a maximum value for object[property].\n *\n * @param {Number} maxValue The maximum value for\n * object[property]\n * @returns {dat.controllers.NumberController} this\n */\n max: function(v) {\n this.__max = v;\n return this;\n },\n\n /**\n * Specify a step value that dat.controllers.NumberController\n * increments by.\n *\n * @param {Number} stepValue The step value for\n * dat.controllers.NumberController\n * @default if minimum and maximum specified increment is 1% of the\n * difference otherwise stepValue is 1\n * @returns {dat.controllers.NumberController} this\n */\n step: function(v) {\n this.__step = v;\n return this;\n }\n\n }\n\n );\n\n function numDecimals(x) {\n x = x.toString();\n if (x.indexOf('.') > -1) {\n return x.length - x.indexOf('.') - 1;\n } else {\n return 0;\n }\n }\n\n return NumberController;\n\n})(dat.controllers.Controller,\ndat.utils.common);\n\n\ndat.controllers.NumberControllerBox = (function (NumberController, dom, common) {\n\n /**\n * @class Represents a given property of an object that is a number and\n * provides an input element with which to manipulate it.\n *\n * @extends dat.controllers.Controller\n * @extends dat.controllers.NumberController\n *\n * @param {Object} object The object to be manipulated\n * @param {string} property The name of the property to be manipulated\n * @param {Object} [params] Optional parameters\n * @param {Number} [params.min] Minimum allowed value\n * @param {Number} [params.max] Maximum allowed value\n * @param {Number} [params.step] Increment by which to change value\n *\n * @member dat.controllers\n */\n var NumberControllerBox = function(object, property, params) {\n\n this.__truncationSuspended = false;\n\n NumberControllerBox.superclass.call(this, object, property, params);\n\n var _this = this;\n\n /**\n * {Number} Previous mouse y position\n * @ignore\n */\n var prev_y;\n\n this.__input = document.createElement('input');\n this.__input.setAttribute('type', 'text');\n\n // Makes it so manually specified values are not truncated.\n\n dom.bind(this.__input, 'change', onChange);\n dom.bind(this.__input, 'blur', onBlur);\n dom.bind(this.__input, 'mousedown', onMouseDown);\n dom.bind(this.__input, 'keydown', function(e) {\n\n // When pressing entire, you can be as precise as you want.\n if (e.keyCode === 13) {\n _this.__truncationSuspended = true;\n this.blur();\n _this.__truncationSuspended = false;\n }\n\n });\n\n function onChange() {\n var attempted = parseFloat(_this.__input.value);\n if (!common.isNaN(attempted)) _this.setValue(attempted);\n }\n\n function onBlur() {\n onChange();\n if (_this.__onFinishChange) {\n _this.__onFinishChange.call(_this, _this.getValue());\n }\n }\n\n function onMouseDown(e) {\n dom.bind(window, 'mousemove', onMouseDrag);\n dom.bind(window, 'mouseup', onMouseUp);\n prev_y = e.clientY;\n }\n\n function onMouseDrag(e) {\n\n var diff = prev_y - e.clientY;\n _this.setValue(_this.getValue() + diff * _this.__impliedStep);\n\n prev_y = e.clientY;\n\n }\n\n function onMouseUp() {\n dom.unbind(window, 'mousemove', onMouseDrag);\n dom.unbind(window, 'mouseup', onMouseUp);\n }\n\n this.updateDisplay();\n\n this.domElement.appendChild(this.__input);\n\n };\n\n NumberControllerBox.superclass = NumberController;\n\n common.extend(\n\n NumberControllerBox.prototype,\n NumberController.prototype,\n\n {\n\n updateDisplay: function() {\n\n this.__input.value = this.__truncationSuspended ? this.getValue() : roundToDecimal(this.getValue(), this.__precision);\n return NumberControllerBox.superclass.prototype.updateDisplay.call(this);\n }\n\n }\n\n );\n\n function roundToDecimal(value, decimals) {\n var tenTo = Math.pow(10, decimals);\n return Math.round(value * tenTo) / tenTo;\n }\n\n return NumberControllerBox;\n\n})(dat.controllers.NumberController,\ndat.dom.dom,\ndat.utils.common);\n\n\ndat.controllers.NumberControllerSlider = (function (NumberController, dom, css, common, styleSheet) {\n\n /**\n * @class Represents a given property of an object that is a number, contains\n * a minimum and maximum, and provides a slider element with which to\n * manipulate it. It should be noted that the slider element is made up of\n * <div> tags, not the html5\n * <slider> element.\n *\n * @extends dat.controllers.Controller\n * @extends dat.controllers.NumberController\n * \n * @param {Object} object The object to be manipulated\n * @param {string} property The name of the property to be manipulated\n * @param {Number} minValue Minimum allowed value\n * @param {Number} maxValue Maximum allowed value\n * @param {Number} stepValue Increment by which to change value\n *\n * @member dat.controllers\n */\n var NumberControllerSlider = function(object, property, min, max, step) {\n\n NumberControllerSlider.superclass.call(this, object, property, { min: min, max: max, step: step });\n\n var _this = this;\n\n this.__background = document.createElement('div');\n this.__foreground = document.createElement('div');\n \n\n\n dom.bind(this.__background, 'mousedown', onMouseDown);\n \n dom.addClass(this.__background, 'slider');\n dom.addClass(this.__foreground, 'slider-fg');\n\n function onMouseDown(e) {\n\n dom.bind(window, 'mousemove', onMouseDrag);\n dom.bind(window, 'mouseup', onMouseUp);\n\n onMouseDrag(e);\n }\n\n function onMouseDrag(e) {\n\n e.preventDefault();\n\n var offset = dom.getOffset(_this.__background);\n var width = dom.getWidth(_this.__background);\n \n _this.setValue(\n map(e.clientX, offset.left, offset.left + width, _this.__min, _this.__max)\n );\n\n return false;\n\n }\n\n function onMouseUp() {\n dom.unbind(window, 'mousemove', onMouseDrag);\n dom.unbind(window, 'mouseup', onMouseUp);\n if (_this.__onFinishChange) {\n _this.__onFinishChange.call(_this, _this.getValue());\n }\n }\n\n this.updateDisplay();\n\n this.__background.appendChild(this.__foreground);\n this.domElement.appendChild(this.__background);\n\n };\n\n NumberControllerSlider.superclass = NumberController;\n\n /**\n * Injects default stylesheet for slider elements.\n */\n NumberControllerSlider.useDefaultStyles = function() {\n css.inject(styleSheet);\n };\n\n common.extend(\n\n NumberControllerSlider.prototype,\n NumberController.prototype,\n\n {\n\n updateDisplay: function() {\n var pct = (this.getValue() - this.__min)/(this.__max - this.__min);\n this.__foreground.style.width = pct*100+'%';\n return NumberControllerSlider.superclass.prototype.updateDisplay.call(this);\n }\n\n }\n\n\n\n );\n\n function map(v, i1, i2, o1, o2) {\n return o1 + (o2 - o1) * ((v - i1) / (i2 - i1));\n }\n\n return NumberControllerSlider;\n \n})(dat.controllers.NumberController,\ndat.dom.dom,\ndat.utils.css,\ndat.utils.common,\n\".slider {\\n box-shadow: inset 0 2px 4px rgba(0,0,0,0.15);\\n height: 1em;\\n border-radius: 1em;\\n background-color: #eee;\\n padding: 0 0.5em;\\n overflow: hidden;\\n}\\n\\n.slider-fg {\\n padding: 1px 0 2px 0;\\n background-color: #aaa;\\n height: 1em;\\n margin-left: -0.5em;\\n padding-right: 0.5em;\\n border-radius: 1em 0 0 1em;\\n}\\n\\n.slider-fg:after {\\n display: inline-block;\\n border-radius: 1em;\\n background-color: #fff;\\n border: 1px solid #aaa;\\n content: '';\\n float: right;\\n margin-right: -1em;\\n margin-top: -1px;\\n height: 0.9em;\\n width: 0.9em;\\n}\");\n\n\ndat.controllers.FunctionController = (function (Controller, dom, common) {\n\n /**\n * @class Provides a GUI interface to fire a specified method, a property of an object.\n *\n * @extends dat.controllers.Controller\n *\n * @param {Object} object The object to be manipulated\n * @param {string} property The name of the property to be manipulated\n *\n * @member dat.controllers\n */\n var FunctionController = function(object, property, text) {\n\n FunctionController.superclass.call(this, object, property);\n\n var _this = this;\n\n this.__button = document.createElement('div');\n this.__button.innerHTML = text === undefined ? 'Fire' : text;\n dom.bind(this.__button, 'click', function(e) {\n e.preventDefault();\n _this.fire();\n return false;\n });\n\n dom.addClass(this.__button, 'button');\n\n this.domElement.appendChild(this.__button);\n\n\n };\n\n FunctionController.superclass = Controller;\n\n common.extend(\n\n FunctionController.prototype,\n Controller.prototype,\n {\n \n fire: function() {\n if (this.__onChange) {\n this.__onChange.call(this);\n }\n if (this.__onFinishChange) {\n this.__onFinishChange.call(this, this.getValue());\n }\n this.getValue().call(this.object);\n }\n }\n\n );\n\n return FunctionController;\n\n})(dat.controllers.Controller,\ndat.dom.dom,\ndat.utils.common);\n\n\ndat.controllers.BooleanController = (function (Controller, dom, common) {\n\n /**\n * @class Provides a checkbox input to alter the boolean property of an object.\n * @extends dat.controllers.Controller\n *\n * @param {Object} object The object to be manipulated\n * @param {string} property The name of the property to be manipulated\n *\n * @member dat.controllers\n */\n var BooleanController = function(object, property) {\n\n BooleanController.superclass.call(this, object, property);\n\n var _this = this;\n this.__prev = this.getValue();\n\n this.__checkbox = document.createElement('input');\n this.__checkbox.setAttribute('type', 'checkbox');\n\n\n dom.bind(this.__checkbox, 'change', onChange, false);\n\n this.domElement.appendChild(this.__checkbox);\n\n // Match original value\n this.updateDisplay();\n\n function onChange() {\n _this.setValue(!_this.__prev);\n }\n\n };\n\n BooleanController.superclass = Controller;\n\n common.extend(\n\n BooleanController.prototype,\n Controller.prototype,\n\n {\n\n setValue: function(v) {\n var toReturn = BooleanController.superclass.prototype.setValue.call(this, v);\n if (this.__onFinishChange) {\n this.__onFinishChange.call(this, this.getValue());\n }\n this.__prev = this.getValue();\n return toReturn;\n },\n\n updateDisplay: function() {\n \n if (this.getValue() === true) {\n this.__checkbox.setAttribute('checked', 'checked');\n this.__checkbox.checked = true; \n } else {\n this.__checkbox.checked = false;\n }\n\n return BooleanController.superclass.prototype.updateDisplay.call(this);\n\n }\n\n\n }\n\n );\n\n return BooleanController;\n\n})(dat.controllers.Controller,\ndat.dom.dom,\ndat.utils.common);\n\n\ndat.color.toString = (function (common) {\n\n return function(color) {\n\n if (color.a == 1 || common.isUndefined(color.a)) {\n\n var s = color.hex.toString(16);\n while (s.length < 6) {\n s = '0' + s;\n }\n\n return '#' + s;\n\n } else {\n\n return 'rgba(' + Math.round(color.r) + ',' + Math.round(color.g) + ',' + Math.round(color.b) + ',' + color.a + ')';\n\n }\n\n }\n\n})(dat.utils.common);\n\n\ndat.color.interpret = (function (toString, common) {\n\n var result, toReturn;\n\n var interpret = function() {\n\n toReturn = false;\n\n var original = arguments.length > 1 ? common.toArray(arguments) : arguments[0];\n\n common.each(INTERPRETATIONS, function(family) {\n\n if (family.litmus(original)) {\n\n common.each(family.conversions, function(conversion, conversionName) {\n\n result = conversion.read(original);\n\n if (toReturn === false && result !== false) {\n toReturn = result;\n result.conversionName = conversionName;\n result.conversion = conversion;\n return common.BREAK;\n\n }\n\n });\n\n return common.BREAK;\n\n }\n\n });\n\n return toReturn;\n\n };\n\n var INTERPRETATIONS = [\n\n // Strings\n {\n\n litmus: common.isString,\n\n conversions: {\n\n THREE_CHAR_HEX: {\n\n read: function(original) {\n\n var test = original.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);\n if (test === null) return false;\n\n return {\n space: 'HEX',\n hex: parseInt(\n '0x' +\n test[1].toString() + test[1].toString() +\n test[2].toString() + test[2].toString() +\n test[3].toString() + test[3].toString())\n };\n\n },\n\n write: toString\n\n },\n\n SIX_CHAR_HEX: {\n\n read: function(original) {\n\n var test = original.match(/^#([A-F0-9]{6})$/i);\n if (test === null) return false;\n\n return {\n space: 'HEX',\n hex: parseInt('0x' + test[1].toString())\n };\n\n },\n\n write: toString\n\n },\n\n CSS_RGB: {\n\n read: function(original) {\n\n var test = original.match(/^rgb\\(\\s*(.+)\\s*,\\s*(.+)\\s*,\\s*(.+)\\s*\\)/);\n if (test === null) return false;\n\n return {\n space: 'RGB',\n r: parseFloat(test[1]),\n g: parseFloat(test[2]),\n b: parseFloat(test[3])\n };\n\n },\n\n write: toString\n\n },\n\n CSS_RGBA: {\n\n read: function(original) {\n\n var test = original.match(/^rgba\\(\\s*(.+)\\s*,\\s*(.+)\\s*,\\s*(.+)\\s*\\,\\s*(.+)\\s*\\)/);\n if (test === null) return false;\n\n return {\n space: 'RGB',\n r: parseFloat(test[1]),\n g: parseFloat(test[2]),\n b: parseFloat(test[3]),\n a: parseFloat(test[4])\n };\n\n },\n\n write: toString\n\n }\n\n }\n\n },\n\n // Numbers\n {\n\n litmus: common.isNumber,\n\n conversions: {\n\n HEX: {\n read: function(original) {\n return {\n space: 'HEX',\n hex: original,\n conversionName: 'HEX'\n }\n },\n\n write: function(color) {\n return color.hex;\n }\n }\n\n }\n\n },\n\n // Arrays\n {\n\n litmus: common.isArray,\n\n conversions: {\n\n RGB_ARRAY: {\n read: function(original) {\n if (original.length != 3) return false;\n return {\n space: 'RGB',\n r: original[0],\n g: original[1],\n b: original[2]\n };\n },\n\n write: function(color) {\n return [color.r, color.g, color.b];\n }\n\n },\n\n RGBA_ARRAY: {\n read: function(original) {\n if (original.length != 4) return false;\n return {\n space: 'RGB',\n r: original[0],\n g: original[1],\n b: original[2],\n a: original[3]\n };\n },\n\n write: function(color) {\n return [color.r, color.g, color.b, color.a];\n }\n\n }\n\n }\n\n },\n\n // Objects\n {\n\n litmus: common.isObject,\n\n conversions: {\n\n RGBA_OBJ: {\n read: function(original) {\n if (common.isNumber(original.r) &&\n common.isNumber(original.g) &&\n common.isNumber(original.b) &&\n common.isNumber(original.a)) {\n return {\n space: 'RGB',\n r: original.r,\n g: original.g,\n b: original.b,\n a: original.a\n }\n }\n return false;\n },\n\n write: function(color) {\n return {\n r: color.r,\n g: color.g,\n b: color.b,\n a: color.a\n }\n }\n },\n\n RGB_OBJ: {\n read: function(original) {\n if (common.isNumber(original.r) &&\n common.isNumber(original.g) &&\n common.isNumber(original.b)) {\n return {\n space: 'RGB',\n r: original.r,\n g: original.g,\n b: original.b\n }\n }\n return false;\n },\n\n write: function(color) {\n return {\n r: color.r,\n g: color.g,\n b: color.b\n }\n }\n },\n\n HSVA_OBJ: {\n read: function(original) {\n if (common.isNumber(original.h) &&\n common.isNumber(original.s) &&\n common.isNumber(original.v) &&\n common.isNumber(original.a)) {\n return {\n space: 'HSV',\n h: original.h,\n s: original.s,\n v: original.v,\n a: original.a\n }\n }\n return false;\n },\n\n write: function(color) {\n return {\n h: color.h,\n s: color.s,\n v: color.v,\n a: color.a\n }\n }\n },\n\n HSV_OBJ: {\n read: function(original) {\n if (common.isNumber(original.h) &&\n common.isNumber(original.s) &&\n common.isNumber(original.v)) {\n return {\n space: 'HSV',\n h: original.h,\n s: original.s,\n v: original.v\n }\n }\n return false;\n },\n\n write: function(color) {\n return {\n h: color.h,\n s: color.s,\n v: color.v\n }\n }\n\n }\n\n }\n\n }\n\n\n ];\n\n return interpret;\n\n\n})(dat.color.toString,\ndat.utils.common);\n\n\ndat.GUI = dat.gui.GUI = (function (css, saveDialogueContents, styleSheet, controllerFactory, Controller, BooleanController, FunctionController, NumberControllerBox, NumberControllerSlider, OptionController, ColorController, requestAnimationFrame, CenteredDiv, dom, common) {\n\n css.inject(styleSheet);\n\n /** Outer-most className for GUI's */\n var CSS_NAMESPACE = 'dg';\n\n var HIDE_KEY_CODE = 72;\n\n /** The only value shared between the JS and SCSS. Use caution. */\n var CLOSE_BUTTON_HEIGHT = 20;\n\n var DEFAULT_DEFAULT_PRESET_NAME = 'Default';\n\n var SUPPORTS_LOCAL_STORAGE = (function() {\n try {\n return 'localStorage' in window && window['localStorage'] !== null;\n } catch (e) {\n return false;\n }\n })();\n\n var SAVE_DIALOGUE;\n\n /** Have we yet to create an autoPlace GUI? */\n var auto_place_virgin = true;\n\n /** Fixed position div that auto place GUI's go inside */\n var auto_place_container;\n\n /** Are we hiding the GUI's ? */\n var hide = false;\n\n /** GUI's which should be hidden */\n var hideable_guis = [];\n\n /**\n * A lightweight controller library for JavaScript. It allows you to easily\n * manipulate variables and fire functions on the fly.\n * @class\n *\n * @member dat.gui\n *\n * @param {Object} [params]\n * @param {String} [params.name] The name of this GUI.\n * @param {Object} [params.load] JSON object representing the saved state of\n * this GUI.\n * @param {Boolean} [params.auto=true]\n * @param {dat.gui.GUI} [params.parent] The GUI I'm nested in.\n * @param {Boolean} [params.closed] If true, starts closed\n */\n var GUI = function(params) {\n\n var _this = this;\n\n /**\n * Outermost DOM Element\n * @type DOMElement\n */\n this.domElement = document.createElement('div');\n this.__ul = document.createElement('ul');\n this.domElement.appendChild(this.__ul);\n\n dom.addClass(this.domElement, CSS_NAMESPACE);\n\n /**\n * Nested GUI's by name\n * @ignore\n */\n this.__folders = {};\n\n this.__controllers = [];\n\n /**\n * List of objects I'm remembering for save, only used in top level GUI\n * @ignore\n */\n this.__rememberedObjects = [];\n\n /**\n * Maps the index of remembered objects to a map of controllers, only used\n * in top level GUI.\n *\n * @private\n * @ignore\n *\n * @example\n * [\n * {\n * propertyName: Controller,\n * anotherPropertyName: Controller\n * },\n * {\n * propertyName: Controller\n * }\n * ]\n */\n this.__rememberedObjectIndecesToControllers = [];\n\n this.__listening = [];\n\n params = params || {};\n\n // Default parameters\n params = common.defaults(params, {\n autoPlace: true,\n width: GUI.DEFAULT_WIDTH\n });\n\n params = common.defaults(params, {\n resizable: params.autoPlace,\n hideable: params.autoPlace\n });\n\n\n if (!common.isUndefined(params.load)) {\n\n // Explicit preset\n if (params.preset) params.load.preset = params.preset;\n\n } else {\n\n params.load = { preset: DEFAULT_DEFAULT_PRESET_NAME };\n\n }\n\n if (common.isUndefined(params.parent) && params.hideable) {\n hideable_guis.push(this);\n }\n\n // Only root level GUI's are resizable.\n params.resizable = common.isUndefined(params.parent) && params.resizable;\n\n\n if (params.autoPlace && common.isUndefined(params.scrollable)) {\n params.scrollable = true;\n }\n// params.scrollable = common.isUndefined(params.parent) && params.scrollable === true;\n\n // Not part of params because I don't want people passing this in via\n // constructor. Should be a 'remembered' value.\n var use_local_storage =\n SUPPORTS_LOCAL_STORAGE &&\n localStorage.getItem(getLocalStorageHash(this, 'isLocal')) === 'true';\n\n Object.defineProperties(this,\n\n /** @lends dat.gui.GUI.prototype */\n {\n\n /**\n * The parent GUI\n * @type dat.gui.GUI\n */\n parent: {\n get: function() {\n return params.parent;\n }\n },\n\n scrollable: {\n get: function() {\n return params.scrollable;\n }\n },\n\n /**\n * Handles GUI's element placement for you\n * @type Boolean\n */\n autoPlace: {\n get: function() {\n return params.autoPlace;\n }\n },\n\n /**\n * The identifier for a set of saved values\n * @type String\n */\n preset: {\n\n get: function() {\n if (_this.parent) {\n return _this.getRoot().preset;\n } else {\n return params.load.preset;\n }\n },\n\n set: function(v) {\n if (_this.parent) {\n _this.getRoot().preset = v;\n } else {\n params.load.preset = v;\n }\n setPresetSelectIndex(this);\n _this.revert();\n }\n\n },\n\n /**\n * The width of GUI element\n * @type Number\n */\n width: {\n get: function() {\n return params.width;\n },\n set: function(v) {\n params.width = v;\n setWidth(_this, v);\n }\n },\n\n /**\n * The name of GUI. Used for folders. i.e\n * a folder's name\n * @type String\n */\n name: {\n get: function() {\n return params.name;\n },\n set: function(v) {\n // TODO Check for collisions among sibling folders\n params.name = v;\n if (title_row_name) {\n title_row_name.innerHTML = params.name;\n }\n }\n },\n\n /**\n * Whether the GUI is collapsed or not\n * @type Boolean\n */\n closed: {\n get: function() {\n return params.closed;\n },\n set: function(v) {\n params.closed = v;\n if (params.closed) {\n dom.addClass(_this.__ul, GUI.CLASS_CLOSED);\n } else {\n dom.removeClass(_this.__ul, GUI.CLASS_CLOSED);\n }\n // For browsers that aren't going to respect the CSS transition,\n // Lets just check our height against the window height right off\n // the bat.\n this.onResize();\n\n if (_this.__closeButton) {\n _this.__closeButton.innerHTML = v ? GUI.TEXT_OPEN : GUI.TEXT_CLOSED;\n }\n }\n },\n\n /**\n * Contains all presets\n * @type Object\n */\n load: {\n get: function() {\n return params.load;\n }\n },\n\n /**\n * Determines whether or not to use localStorage as the means for\n * remembering\n * @type Boolean\n */\n useLocalStorage: {\n\n get: function() {\n return use_local_storage;\n },\n set: function(bool) {\n if (SUPPORTS_LOCAL_STORAGE) {\n use_local_storage = bool;\n if (bool) {\n dom.bind(window, 'unload', saveToLocalStorage);\n } else {\n dom.unbind(window, 'unload', saveToLocalStorage);\n }\n localStorage.setItem(getLocalStorageHash(_this, 'isLocal'), bool);\n }\n }\n\n }\n\n });\n\n // Are we a root level GUI?\n if (common.isUndefined(params.parent)) {\n\n params.closed = false;\n\n dom.addClass(this.domElement, GUI.CLASS_MAIN);\n dom.makeSelectable(this.domElement, false);\n\n // Are we supposed to be loading locally?\n if (SUPPORTS_LOCAL_STORAGE) {\n\n if (use_local_storage) {\n\n _this.useLocalStorage = true;\n\n var saved_gui = localStorage.getItem(getLocalStorageHash(this, 'gui'));\n\n if (saved_gui) {\n params.load = JSON.parse(saved_gui);\n }\n\n }\n\n }\n\n this.__closeButton = document.createElement('div');\n this.__closeButton.innerHTML = GUI.TEXT_CLOSED;\n dom.addClass(this.__closeButton, GUI.CLASS_CLOSE_BUTTON);\n this.domElement.appendChild(this.__closeButton);\n\n dom.bind(this.__closeButton, 'click', function() {\n\n _this.closed = !_this.closed;\n\n\n });\n\n\n // Oh, you're a nested GUI!\n } else {\n\n if (params.closed === undefined) {\n params.closed = true;\n }\n\n var title_row_name = document.createTextNode(params.name);\n dom.addClass(title_row_name, 'controller-name');\n\n var title_row = addRow(_this, title_row_name);\n\n var on_click_title = function(e) {\n e.preventDefault();\n _this.closed = !_this.closed;\n return false;\n };\n\n dom.addClass(this.__ul, GUI.CLASS_CLOSED);\n\n dom.addClass(title_row, 'title');\n dom.bind(title_row, 'click', on_click_title);\n\n if (!params.closed) {\n this.closed = false;\n }\n\n }\n\n if (params.autoPlace) {\n\n if (common.isUndefined(params.parent)) {\n\n if (auto_place_virgin) {\n auto_place_container = document.createElement('div');\n dom.addClass(auto_place_container, CSS_NAMESPACE);\n dom.addClass(auto_place_container, GUI.CLASS_AUTO_PLACE_CONTAINER);\n document.body.appendChild(auto_place_container);\n auto_place_virgin = false;\n }\n\n // Put it in the dom for you.\n auto_place_container.appendChild(this.domElement);\n\n // Apply the auto styles\n dom.addClass(this.domElement, GUI.CLASS_AUTO_PLACE);\n\n }\n\n\n // Make it not elastic.\n if (!this.parent) setWidth(_this, params.width);\n\n }\n\n dom.bind(window, 'resize', function() { _this.onResize() });\n dom.bind(this.__ul, 'webkitTransitionEnd', function() { _this.onResize(); });\n dom.bind(this.__ul, 'transitionend', function() { _this.onResize() });\n dom.bind(this.__ul, 'oTransitionEnd', function() { _this.onResize() });\n this.onResize();\n\n\n if (params.resizable) {\n addResizeHandle(this);\n }\n\n function saveToLocalStorage() {\n localStorage.setItem(getLocalStorageHash(_this, 'gui'), JSON.stringify(_this.getSaveObject()));\n }\n\n var root = _this.getRoot();\n function resetWidth() {\n var root = _this.getRoot();\n root.width += 1;\n common.defer(function() {\n root.width -= 1;\n });\n }\n\n if (!params.parent) {\n resetWidth();\n }\n\n };\n\n GUI.toggleHide = function() {\n\n hide = !hide;\n common.each(hideable_guis, function(gui) {\n gui.domElement.style.zIndex = hide ? -999 : 999;\n gui.domElement.style.opacity = hide ? 0 : 1;\n });\n };\n\n GUI.CLASS_AUTO_PLACE = 'a';\n GUI.CLASS_AUTO_PLACE_CONTAINER = 'ac';\n GUI.CLASS_MAIN = 'main';\n GUI.CLASS_CONTROLLER_ROW = 'cr';\n GUI.CLASS_TOO_TALL = 'taller-than-window';\n GUI.CLASS_CLOSED = 'closed';\n GUI.CLASS_CLOSE_BUTTON = 'close-button';\n GUI.CLASS_DRAG = 'drag';\n\n GUI.DEFAULT_WIDTH = 245;\n GUI.TEXT_CLOSED = 'Close Controls';\n GUI.TEXT_OPEN = 'Open Controls';\n\n dom.bind(window, 'keydown', function(e) {\n\n if (document.activeElement.type !== 'text' &&\n (e.which === HIDE_KEY_CODE || e.keyCode == HIDE_KEY_CODE)) {\n GUI.toggleHide();\n }\n\n }, false);\n\n common.extend(\n\n GUI.prototype,\n\n /** @lends dat.gui.GUI */\n {\n\n /**\n * @param object\n * @param property\n * @returns {dat.controllers.Controller} The new controller that was added.\n * @instance\n */\n add: function(object, property) {\n\n return add(\n this,\n object,\n property,\n {\n factoryArgs: Array.prototype.slice.call(arguments, 2)\n }\n );\n\n },\n\n /**\n * @param object\n * @param property\n * @returns {dat.controllers.ColorController} The new controller that was added.\n * @instance\n */\n addColor: function(object, property) {\n\n return add(\n this,\n object,\n property,\n {\n color: true\n }\n );\n\n },\n\n /**\n * @param controller\n * @instance\n */\n remove: function(controller) {\n\n // TODO listening?\n this.__ul.removeChild(controller.__li);\n this.__controllers.slice(this.__controllers.indexOf(controller), 1);\n var _this = this;\n common.defer(function() {\n _this.onResize();\n });\n\n },\n\n destroy: function() {\n\n if (this.autoPlace) {\n auto_place_container.removeChild(this.domElement);\n }\n\n },\n\n /**\n * @param name\n * @returns {dat.gui.GUI} The new folder.\n * @throws {Error} if this GUI already has a folder by the specified\n * name\n * @instance\n */\n addFolder: function(name) {\n\n // We have to prevent collisions on names in order to have a key\n // by which to remember saved values\n if (this.__folders[name] !== undefined) {\n throw new Error('You already have a folder in this GUI by the' +\n ' name \"' + name + '\"');\n }\n\n var new_gui_params = { name: name, parent: this };\n\n // We need to pass down the autoPlace trait so that we can\n // attach event listeners to open/close folder actions to\n // ensure that a scrollbar appears if the window is too short.\n new_gui_params.autoPlace = this.autoPlace;\n\n // Do we have saved appearance data for this folder?\n\n if (this.load && // Anything loaded?\n this.load.folders && // Was my parent a dead-end?\n this.load.folders[name]) { // Did daddy remember me?\n\n // Start me closed if I was closed\n new_gui_params.closed = this.load.folders[name].closed;\n\n // Pass down the loaded data\n new_gui_params.load = this.load.folders[name];\n\n }\n\n var gui = new GUI(new_gui_params);\n this.__folders[name] = gui;\n\n var li = addRow(this, gui.domElement);\n dom.addClass(li, 'folder');\n return gui;\n\n },\n\n open: function() {\n this.closed = false;\n },\n\n close: function() {\n this.closed = true;\n },\n\n onResize: function() {\n\n var root = this.getRoot();\n\n if (root.scrollable) {\n\n var top = dom.getOffset(root.__ul).top;\n var h = 0;\n\n common.each(root.__ul.childNodes, function(node) {\n if (! (root.autoPlace && node === root.__save_row))\n h += dom.getHeight(node);\n });\n\n if (window.innerHeight - top - CLOSE_BUTTON_HEIGHT < h) {\n dom.addClass(root.domElement, GUI.CLASS_TOO_TALL);\n root.__ul.style.height = window.innerHeight - top - CLOSE_BUTTON_HEIGHT + 'px';\n } else {\n dom.removeClass(root.domElement, GUI.CLASS_TOO_TALL);\n root.__ul.style.height = 'auto';\n }\n\n }\n\n if (root.__resize_handle) {\n common.defer(function() {\n root.__resize_handle.style.height = root.__ul.offsetHeight + 'px';\n });\n }\n\n if (root.__closeButton) {\n root.__closeButton.style.width = root.width + 'px';\n }\n\n },\n\n /**\n * Mark objects for saving. The order of these objects cannot change as\n * the GUI grows. When remembering new objects, append them to the end\n * of the list.\n *\n * @param {Object...} objects\n * @throws {Error} if not called on a top level GUI.\n * @instance\n */\n remember: function() {\n\n if (common.isUndefined(SAVE_DIALOGUE)) {\n SAVE_DIALOGUE = new CenteredDiv();\n SAVE_DIALOGUE.domElement.innerHTML = saveDialogueContents;\n }\n\n if (this.parent) {\n throw new Error(\"You can only call remember on a top level GUI.\");\n }\n\n var _this = this;\n\n common.each(Array.prototype.slice.call(arguments), function(object) {\n if (_this.__rememberedObjects.length == 0) {\n addSaveMenu(_this);\n }\n if (_this.__rememberedObjects.indexOf(object) == -1) {\n _this.__rememberedObjects.push(object);\n }\n });\n\n if (this.autoPlace) {\n // Set save row width\n setWidth(this, this.width);\n }\n\n },\n\n /**\n * @returns {dat.gui.GUI} the topmost parent GUI of a nested GUI.\n * @instance\n */\n getRoot: function() {\n var gui = this;\n while (gui.parent) {\n gui = gui.parent;\n }\n return gui;\n },\n\n /**\n * @returns {Object} a JSON object representing the current state of\n * this GUI as well as its remembered properties.\n * @instance\n */\n getSaveObject: function() {\n\n var toReturn = this.load;\n\n toReturn.closed = this.closed;\n\n // Am I remembering any values?\n if (this.__rememberedObjects.length > 0) {\n\n toReturn.preset = this.preset;\n\n if (!toReturn.remembered) {\n toReturn.remembered = {};\n }\n\n toReturn.remembered[this.preset] = getCurrentPreset(this);\n\n }\n\n toReturn.folders = {};\n common.each(this.__folders, function(element, key) {\n toReturn.folders[key] = element.getSaveObject();\n });\n\n return toReturn;\n\n },\n\n save: function() {\n\n if (!this.load.remembered) {\n this.load.remembered = {};\n }\n\n this.load.remembered[this.preset] = getCurrentPreset(this);\n markPresetModified(this, false);\n\n },\n\n saveAs: function(presetName) {\n\n if (!this.load.remembered) {\n\n // Retain default values upon first save\n this.load.remembered = {};\n this.load.remembered[DEFAULT_DEFAULT_PRESET_NAME] = getCurrentPreset(this, true);\n\n }\n\n this.load.remembered[presetName] = getCurrentPreset(this);\n this.preset = presetName;\n addPresetOption(this, presetName, true);\n\n },\n\n revert: function(gui) {\n\n common.each(this.__controllers, function(controller) {\n // Make revert work on Default.\n if (!this.getRoot().load.remembered) {\n controller.setValue(controller.initialValue);\n } else {\n recallSavedValue(gui || this.getRoot(), controller);\n }\n }, this);\n\n common.each(this.__folders, function(folder) {\n folder.revert(folder);\n });\n\n if (!gui) {\n markPresetModified(this.getRoot(), false);\n }\n\n\n },\n\n listen: function(controller) {\n\n var init = this.__listening.length == 0;\n this.__listening.push(controller);\n if (init) updateDisplays(this.__listening);\n\n }\n\n }\n\n );\n\n function add(gui, object, property, params) {\n\n if (object[property] === undefined) {\n throw new Error(\"Object \" + object + \" has no property \\\"\" + property + \"\\\"\");\n }\n\n var controller;\n\n if (params.color) {\n\n controller = new ColorController(object, property);\n\n } else {\n\n var factoryArgs = [object,property].concat(params.factoryArgs);\n controller = controllerFactory.apply(gui, factoryArgs);\n\n }\n\n if (params.before instanceof Controller) {\n params.before = params.before.__li;\n }\n\n recallSavedValue(gui, controller);\n\n dom.addClass(controller.domElement, 'c');\n\n var name = document.createElement('span');\n dom.addClass(name, 'property-name');\n name.innerHTML = controller.property;\n\n var container = document.createElement('div');\n container.appendChild(name);\n container.appendChild(controller.domElement);\n\n var li = addRow(gui, container, params.before);\n\n dom.addClass(li, GUI.CLASS_CONTROLLER_ROW);\n dom.addClass(li, typeof controller.getValue());\n\n augmentController(gui, li, controller);\n\n gui.__controllers.push(controller);\n\n return controller;\n\n }\n\n /**\n * Add a row to the end of the GUI or before another row.\n *\n * @param gui\n * @param [dom] If specified, inserts the dom content in the new row\n * @param [liBefore] If specified, places the new row before another row\n */\n function addRow(gui, dom, liBefore) {\n var li = document.createElement('li');\n if (dom) li.appendChild(dom);\n if (liBefore) {\n gui.__ul.insertBefore(li, params.before);\n } else {\n gui.__ul.appendChild(li);\n }\n gui.onResize();\n return li;\n }\n\n function augmentController(gui, li, controller) {\n\n controller.__li = li;\n controller.__gui = gui;\n\n common.extend(controller, {\n\n options: function(options) {\n\n if (arguments.length > 1) {\n controller.remove();\n\n return add(\n gui,\n controller.object,\n controller.property,\n {\n before: controller.__li.nextElementSibling,\n factoryArgs: [common.toArray(arguments)]\n }\n );\n\n }\n\n if (common.isArray(options) || common.isObject(options)) {\n controller.remove();\n\n return add(\n gui,\n controller.object,\n controller.property,\n {\n before: controller.__li.nextElementSibling,\n factoryArgs: [options]\n }\n );\n\n }\n\n },\n\n name: function(v) {\n controller.__li.firstElementChild.firstElementChild.innerHTML = v;\n return controller;\n },\n\n listen: function() {\n controller.__gui.listen(controller);\n return controller;\n },\n\n remove: function() {\n controller.__gui.remove(controller);\n return controller;\n }\n\n });\n\n // All sliders should be accompanied by a box.\n if (controller instanceof NumberControllerSlider) {\n\n var box = new NumberControllerBox(controller.object, controller.property,\n { min: controller.__min, max: controller.__max, step: controller.__step });\n\n common.each(['updateDisplay', 'onChange', 'onFinishChange'], function(method) {\n var pc = controller[method];\n var pb = box[method];\n controller[method] = box[method] = function() {\n var args = Array.prototype.slice.call(arguments);\n pc.apply(controller, args);\n return pb.apply(box, args);\n }\n });\n\n dom.addClass(li, 'has-slider');\n controller.domElement.insertBefore(box.domElement, controller.domElement.firstElementChild);\n\n }\n else if (controller instanceof NumberControllerBox) {\n\n var r = function(returned) {\n\n // Have we defined both boundaries?\n if (common.isNumber(controller.__min) && common.isNumber(controller.__max)) {\n\n // Well, then lets just replace this with a slider.\n controller.remove();\n return add(\n gui,\n controller.object,\n controller.property,\n {\n before: controller.__li.nextElementSibling,\n factoryArgs: [controller.__min, controller.__max, controller.__step]\n });\n\n }\n\n return returned;\n\n };\n\n controller.min = common.compose(r, controller.min);\n controller.max = common.compose(r, controller.max);\n\n }\n else if (controller instanceof BooleanController) {\n\n dom.bind(li, 'click', function() {\n dom.fakeEvent(controller.__checkbox, 'click');\n });\n\n dom.bind(controller.__checkbox, 'click', function(e) {\n e.stopPropagation(); // Prevents double-toggle\n })\n\n }\n else if (controller instanceof FunctionController) {\n\n dom.bind(li, 'click', function() {\n dom.fakeEvent(controller.__button, 'click');\n });\n\n dom.bind(li, 'mouseover', function() {\n dom.addClass(controller.__button, 'hover');\n });\n\n dom.bind(li, 'mouseout', function() {\n dom.removeClass(controller.__button, 'hover');\n });\n\n }\n else if (controller instanceof ColorController) {\n\n dom.addClass(li, 'color');\n controller.updateDisplay = common.compose(function(r) {\n li.style.borderLeftColor = controller.__color.toString();\n return r;\n }, controller.updateDisplay);\n\n controller.updateDisplay();\n\n }\n\n controller.setValue = common.compose(function(r) {\n if (gui.getRoot().__preset_select && controller.isModified()) {\n markPresetModified(gui.getRoot(), true);\n }\n return r;\n }, controller.setValue);\n\n }\n\n function recallSavedValue(gui, controller) {\n\n // Find the topmost GUI, that's where remembered objects live.\n var root = gui.getRoot();\n\n // Does the object we're controlling match anything we've been told to\n // remember?\n var matched_index = root.__rememberedObjects.indexOf(controller.object);\n\n // Why yes, it does!\n if (matched_index != -1) {\n\n // Let me fetch a map of controllers for thcommon.isObject.\n var controller_map =\n root.__rememberedObjectIndecesToControllers[matched_index];\n\n // Ohp, I believe this is the first controller we've created for this\n // object. Lets make the map fresh.\n if (controller_map === undefined) {\n controller_map = {};\n root.__rememberedObjectIndecesToControllers[matched_index] =\n controller_map;\n }\n\n // Keep track of this controller\n controller_map[controller.property] = controller;\n\n // Okay, now have we saved any values for this controller?\n if (root.load && root.load.remembered) {\n\n var preset_map = root.load.remembered;\n\n // Which preset are we trying to load?\n var preset;\n\n if (preset_map[gui.preset]) {\n\n preset = preset_map[gui.preset];\n\n } else if (preset_map[DEFAULT_DEFAULT_PRESET_NAME]) {\n\n // Uhh, you can have the default instead?\n preset = preset_map[DEFAULT_DEFAULT_PRESET_NAME];\n\n } else {\n\n // Nada.\n\n return;\n\n }\n\n\n // Did the loaded object remember thcommon.isObject?\n if (preset[matched_index] &&\n\n // Did we remember this particular property?\n preset[matched_index][controller.property] !== undefined) {\n\n // We did remember something for this guy ...\n var value = preset[matched_index][controller.property];\n\n // And that's what it is.\n controller.initialValue = value;\n controller.setValue(value);\n\n }\n\n }\n\n }\n\n }\n\n function getLocalStorageHash(gui, key) {\n // TODO how does this deal with multiple GUI's?\n return document.location.href + '.' + key;\n\n }\n\n function addSaveMenu(gui) {\n\n var div = gui.__save_row = document.createElement('li');\n\n dom.addClass(gui.domElement, 'has-save');\n\n gui.__ul.insertBefore(div, gui.__ul.firstChild);\n\n dom.addClass(div, 'save-row');\n\n var gears = document.createElement('span');\n gears.innerHTML = ' ';\n dom.addClass(gears, 'button gears');\n\n // TODO replace with FunctionController\n var button = document.createElement('span');\n button.innerHTML = 'Save';\n dom.addClass(button, 'button');\n dom.addClass(button, 'save');\n\n var button2 = document.createElement('span');\n button2.innerHTML = 'New';\n dom.addClass(button2, 'button');\n dom.addClass(button2, 'save-as');\n\n var button3 = document.createElement('span');\n button3.innerHTML = 'Revert';\n dom.addClass(button3, 'button');\n dom.addClass(button3, 'revert');\n\n var select = gui.__preset_select = document.createElement('select');\n\n if (gui.load && gui.load.remembered) {\n\n common.each(gui.load.remembered, function(value, key) {\n addPresetOption(gui, key, key == gui.preset);\n });\n\n } else {\n addPresetOption(gui, DEFAULT_DEFAULT_PRESET_NAME, false);\n }\n\n dom.bind(select, 'change', function() {\n\n\n for (var index = 0; index < gui.__preset_select.length; index++) {\n gui.__preset_select[index].innerHTML = gui.__preset_select[index].value;\n }\n\n gui.preset = this.value;\n\n });\n\n div.appendChild(select);\n div.appendChild(gears);\n div.appendChild(button);\n div.appendChild(button2);\n div.appendChild(button3);\n\n if (SUPPORTS_LOCAL_STORAGE) {\n\n var saveLocally = document.getElementById('dg-save-locally');\n var explain = document.getElementById('dg-local-explain');\n\n saveLocally.style.display = 'block';\n\n var localStorageCheckBox = document.getElementById('dg-local-storage');\n\n if (localStorage.getItem(getLocalStorageHash(gui, 'isLocal')) === 'true') {\n localStorageCheckBox.setAttribute('checked', 'checked');\n }\n\n function showHideExplain() {\n explain.style.display = gui.useLocalStorage ? 'block' : 'none';\n }\n\n showHideExplain();\n\n // TODO: Use a boolean controller, fool!\n dom.bind(localStorageCheckBox, 'change', function() {\n gui.useLocalStorage = !gui.useLocalStorage;\n showHideExplain();\n });\n\n }\n\n var newConstructorTextArea = document.getElementById('dg-new-constructor');\n\n dom.bind(newConstructorTextArea, 'keydown', function(e) {\n if (e.metaKey && (e.which === 67 || e.keyCode == 67)) {\n SAVE_DIALOGUE.hide();\n }\n });\n\n dom.bind(gears, 'click', function() {\n newConstructorTextArea.innerHTML = JSON.stringify(gui.getSaveObject(), undefined, 2);\n SAVE_DIALOGUE.show();\n newConstructorTextArea.focus();\n newConstructorTextArea.select();\n });\n\n dom.bind(button, 'click', function() {\n gui.save();\n });\n\n dom.bind(button2, 'click', function() {\n var presetName = prompt('Enter a new preset name.');\n if (presetName) gui.saveAs(presetName);\n });\n\n dom.bind(button3, 'click', function() {\n gui.revert();\n });\n\n// div.appendChild(button2);\n\n }\n\n function addResizeHandle(gui) {\n\n gui.__resize_handle = document.createElement('div');\n\n common.extend(gui.__resize_handle.style, {\n\n width: '6px',\n marginLeft: '-3px',\n height: '200px',\n cursor: 'ew-resize',\n position: 'absolute'\n// border: '1px solid blue'\n\n });\n\n var pmouseX;\n\n dom.bind(gui.__resize_handle, 'mousedown', dragStart);\n dom.bind(gui.__closeButton, 'mousedown', dragStart);\n\n gui.domElement.insertBefore(gui.__resize_handle, gui.domElement.firstElementChild);\n\n function dragStart(e) {\n\n e.preventDefault();\n\n pmouseX = e.clientX;\n\n dom.addClass(gui.__closeButton, GUI.CLASS_DRAG);\n dom.bind(window, 'mousemove', drag);\n dom.bind(window, 'mouseup', dragStop);\n\n return false;\n\n }\n\n function drag(e) {\n\n e.preventDefault();\n\n gui.width += pmouseX - e.clientX;\n gui.onResize();\n pmouseX = e.clientX;\n\n return false;\n\n }\n\n function dragStop() {\n\n dom.removeClass(gui.__closeButton, GUI.CLASS_DRAG);\n dom.unbind(window, 'mousemove', drag);\n dom.unbind(window, 'mouseup', dragStop);\n\n }\n\n }\n\n function setWidth(gui, w) {\n gui.domElement.style.width = w + 'px';\n // Auto placed save-rows are position fixed, so we have to\n // set the width manually if we want it to bleed to the edge\n if (gui.__save_row && gui.autoPlace) {\n gui.__save_row.style.width = w + 'px';\n }if (gui.__closeButton) {\n gui.__closeButton.style.width = w + 'px';\n }\n }\n\n function getCurrentPreset(gui, useInitialValues) {\n\n var toReturn = {};\n\n // For each object I'm remembering\n common.each(gui.__rememberedObjects, function(val, index) {\n\n var saved_values = {};\n\n // The controllers I've made for thcommon.isObject by property\n var controller_map =\n gui.__rememberedObjectIndecesToControllers[index];\n\n // Remember each value for each property\n common.each(controller_map, function(controller, property) {\n saved_values[property] = useInitialValues ? controller.initialValue : controller.getValue();\n });\n\n // Save the values for thcommon.isObject\n toReturn[index] = saved_values;\n\n });\n\n return toReturn;\n\n }\n\n function addPresetOption(gui, name, setSelected) {\n var opt = document.createElement('option');\n opt.innerHTML = name;\n opt.value = name;\n gui.__preset_select.appendChild(opt);\n if (setSelected) {\n gui.__preset_select.selectedIndex = gui.__preset_select.length - 1;\n }\n }\n\n function setPresetSelectIndex(gui) {\n for (var index = 0; index < gui.__preset_select.length; index++) {\n if (gui.__preset_select[index].value == gui.preset) {\n gui.__preset_select.selectedIndex = index;\n }\n }\n }\n\n function markPresetModified(gui, modified) {\n var opt = gui.__preset_select[gui.__preset_select.selectedIndex];\n// console.log('mark', modified, opt);\n if (modified) {\n opt.innerHTML = opt.value + \"*\";\n } else {\n opt.innerHTML = opt.value;\n }\n }\n\n function updateDisplays(controllerArray) {\n\n\n if (controllerArray.length != 0) {\n\n requestAnimationFrame(function() {\n updateDisplays(controllerArray);\n });\n\n }\n\n common.each(controllerArray, function(c) {\n c.updateDisplay();\n });\n\n }\n\n return GUI;\n\n})(dat.utils.css,\n\"
\\n\\n Here's the new load parameter for your GUI's constructor:\\n\\n \\n\\n
\\n\\n Automatically save\\n values to localStorage on exit.\\n\\n
The values saved to localStorage will\\n override those passed to dat.GUI's constructor. This makes it\\n easier to work incrementally, but localStorage is fragile,\\n and your friends may not see the same values you do.\\n \\n
\\n \\n
\\n\\n
\",\n\".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity 0.1s linear;-o-transition:opacity 0.1s linear;-moz-transition:opacity 0.1s linear;transition:opacity 0.1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1 !important}.dg.main:hover .close-button,.dg.main .close-button.drag{opacity:1}.dg.main .close-button{-webkit-transition:opacity 0.1s linear;-o-transition:opacity 0.1s linear;-moz-transition:opacity 0.1s linear;transition:opacity 0.1s linear;border:0;position:absolute;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-x:hidden}.dg.a.has-save ul{margin-top:27px}.dg.a.has-save ul.closed{margin-top:0}.dg.a .save-row{position:fixed;top:0;z-index:1002}.dg li{-webkit-transition:height 0.1s ease-out;-o-transition:height 0.1s ease-out;-moz-transition:height 0.1s ease-out;transition:height 0.1s ease-out}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;overflow:hidden;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid rgba(0,0,0,0)}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li > *{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:9px}.dg .c select{margin-top:5px}.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{cursor:pointer}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0px 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco, monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px 'Lucida Grande', sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px 4px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid rgba(255,255,255,0.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2fa1d6}.dg .cr.number input[type=text]{color:#2fa1d6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.function:hover,.dg .cr.boolean:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2fa1d6}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}\\n\",\ndat.controllers.factory = (function (OptionController, NumberControllerBox, NumberControllerSlider, StringController, FunctionController, BooleanController, common) {\n\n return function(object, property) {\n\n var initialValue = object[property];\n\n // Providing options?\n if (common.isArray(arguments[2]) || common.isObject(arguments[2])) {\n return new OptionController(object, property, arguments[2]);\n }\n\n // Providing a map?\n\n if (common.isNumber(initialValue)) {\n\n if (common.isNumber(arguments[2]) && common.isNumber(arguments[3])) {\n\n // Has min and max.\n return new NumberControllerSlider(object, property, arguments[2], arguments[3]);\n\n } else {\n\n return new NumberControllerBox(object, property, { min: arguments[2], max: arguments[3] });\n\n }\n\n }\n\n if (common.isString(initialValue)) {\n return new StringController(object, property);\n }\n\n if (common.isFunction(initialValue)) {\n return new FunctionController(object, property, '');\n }\n\n if (common.isBoolean(initialValue)) {\n return new BooleanController(object, property);\n }\n\n }\n\n })(dat.controllers.OptionController,\ndat.controllers.NumberControllerBox,\ndat.controllers.NumberControllerSlider,\ndat.controllers.StringController = (function (Controller, dom, common) {\n\n /**\n * @class Provides a text input to alter the string property of an object.\n *\n * @extends dat.controllers.Controller\n *\n * @param {Object} object The object to be manipulated\n * @param {string} property The name of the property to be manipulated\n *\n * @member dat.controllers\n */\n var StringController = function(object, property) {\n\n StringController.superclass.call(this, object, property);\n\n var _this = this;\n\n this.__input = document.createElement('input');\n this.__input.setAttribute('type', 'text');\n\n dom.bind(this.__input, 'keyup', onChange);\n dom.bind(this.__input, 'change', onChange);\n dom.bind(this.__input, 'blur', onBlur);\n dom.bind(this.__input, 'keydown', function(e) {\n if (e.keyCode === 13) {\n this.blur();\n }\n });\n \n\n function onChange() {\n _this.setValue(_this.__input.value);\n }\n\n function onBlur() {\n if (_this.__onFinishChange) {\n _this.__onFinishChange.call(_this, _this.getValue());\n }\n }\n\n this.updateDisplay();\n\n this.domElement.appendChild(this.__input);\n\n };\n\n StringController.superclass = Controller;\n\n common.extend(\n\n StringController.prototype,\n Controller.prototype,\n\n {\n\n updateDisplay: function() {\n // Stops the caret from moving on account of:\n // keyup -> setValue -> updateDisplay\n if (!dom.isActive(this.__input)) {\n this.__input.value = this.getValue();\n }\n return StringController.superclass.prototype.updateDisplay.call(this);\n }\n\n }\n\n );\n\n return StringController;\n\n})(dat.controllers.Controller,\ndat.dom.dom,\ndat.utils.common),\ndat.controllers.FunctionController,\ndat.controllers.BooleanController,\ndat.utils.common),\ndat.controllers.Controller,\ndat.controllers.BooleanController,\ndat.controllers.FunctionController,\ndat.controllers.NumberControllerBox,\ndat.controllers.NumberControllerSlider,\ndat.controllers.OptionController,\ndat.controllers.ColorController = (function (Controller, dom, Color, interpret, common) {\n\n var ColorController = function(object, property) {\n\n ColorController.superclass.call(this, object, property);\n\n this.__color = new Color(this.getValue());\n this.__temp = new Color(0);\n\n var _this = this;\n\n this.domElement = document.createElement('div');\n\n dom.makeSelectable(this.domElement, false);\n\n this.__selector = document.createElement('div');\n this.__selector.className = 'selector';\n\n this.__saturation_field = document.createElement('div');\n this.__saturation_field.className = 'saturation-field';\n\n this.__field_knob = document.createElement('div');\n this.__field_knob.className = 'field-knob';\n this.__field_knob_border = '2px solid ';\n\n this.__hue_knob = document.createElement('div');\n this.__hue_knob.className = 'hue-knob';\n\n this.__hue_field = document.createElement('div');\n this.__hue_field.className = 'hue-field';\n\n this.__input = document.createElement('input');\n this.__input.type = 'text';\n this.__input_textShadow = '0 1px 1px ';\n\n dom.bind(this.__input, 'keydown', function(e) {\n if (e.keyCode === 13) { // on enter\n onBlur.call(this);\n }\n });\n\n dom.bind(this.__input, 'blur', onBlur);\n\n dom.bind(this.__selector, 'mousedown', function(e) {\n\n dom\n .addClass(this, 'drag')\n .bind(window, 'mouseup', function(e) {\n dom.removeClass(_this.__selector, 'drag');\n });\n\n });\n\n var value_field = document.createElement('div');\n\n common.extend(this.__selector.style, {\n width: '122px',\n height: '102px',\n padding: '3px',\n backgroundColor: '#222',\n boxShadow: '0px 1px 3px rgba(0,0,0,0.3)'\n });\n\n common.extend(this.__field_knob.style, {\n position: 'absolute',\n width: '12px',\n height: '12px',\n border: this.__field_knob_border + (this.__color.v < .5 ? '#fff' : '#000'),\n boxShadow: '0px 1px 3px rgba(0,0,0,0.5)',\n borderRadius: '12px',\n zIndex: 1\n });\n \n common.extend(this.__hue_knob.style, {\n position: 'absolute',\n width: '15px',\n height: '2px',\n borderRight: '4px solid #fff',\n zIndex: 1\n });\n\n common.extend(this.__saturation_field.style, {\n width: '100px',\n height: '100px',\n border: '1px solid #555',\n marginRight: '3px',\n display: 'inline-block',\n cursor: 'pointer'\n });\n\n common.extend(value_field.style, {\n width: '100%',\n height: '100%',\n background: 'none'\n });\n \n linearGradient(value_field, 'top', 'rgba(0,0,0,0)', '#000');\n\n common.extend(this.__hue_field.style, {\n width: '15px',\n height: '100px',\n display: 'inline-block',\n border: '1px solid #555',\n cursor: 'ns-resize'\n });\n\n hueGradient(this.__hue_field);\n\n common.extend(this.__input.style, {\n outline: 'none',\n// width: '120px',\n textAlign: 'center',\n// padding: '4px',\n// marginBottom: '6px',\n color: '#fff',\n border: 0,\n fontWeight: 'bold',\n textShadow: this.__input_textShadow + 'rgba(0,0,0,0.7)'\n });\n\n dom.bind(this.__saturation_field, 'mousedown', fieldDown);\n dom.bind(this.__field_knob, 'mousedown', fieldDown);\n\n dom.bind(this.__hue_field, 'mousedown', function(e) {\n setH(e);\n dom.bind(window, 'mousemove', setH);\n dom.bind(window, 'mouseup', unbindH);\n });\n\n function fieldDown(e) {\n setSV(e);\n // document.body.style.cursor = 'none';\n dom.bind(window, 'mousemove', setSV);\n dom.bind(window, 'mouseup', unbindSV);\n }\n\n function unbindSV() {\n dom.unbind(window, 'mousemove', setSV);\n dom.unbind(window, 'mouseup', unbindSV);\n // document.body.style.cursor = 'default';\n }\n\n function onBlur() {\n var i = interpret(this.value);\n if (i !== false) {\n _this.__color.__state = i;\n _this.setValue(_this.__color.toOriginal());\n } else {\n this.value = _this.__color.toString();\n }\n }\n\n function unbindH() {\n dom.unbind(window, 'mousemove', setH);\n dom.unbind(window, 'mouseup', unbindH);\n }\n\n this.__saturation_field.appendChild(value_field);\n this.__selector.appendChild(this.__field_knob);\n this.__selector.appendChild(this.__saturation_field);\n this.__selector.appendChild(this.__hue_field);\n this.__hue_field.appendChild(this.__hue_knob);\n\n this.domElement.appendChild(this.__input);\n this.domElement.appendChild(this.__selector);\n\n this.updateDisplay();\n\n function setSV(e) {\n\n e.preventDefault();\n\n var w = dom.getWidth(_this.__saturation_field);\n var o = dom.getOffset(_this.__saturation_field);\n var s = (e.clientX - o.left + document.body.scrollLeft) / w;\n var v = 1 - (e.clientY - o.top + document.body.scrollTop) / w;\n\n if (v > 1) v = 1;\n else if (v < 0) v = 0;\n\n if (s > 1) s = 1;\n else if (s < 0) s = 0;\n\n _this.__color.v = v;\n _this.__color.s = s;\n\n _this.setValue(_this.__color.toOriginal());\n\n\n return false;\n\n }\n\n function setH(e) {\n\n e.preventDefault();\n\n var s = dom.getHeight(_this.__hue_field);\n var o = dom.getOffset(_this.__hue_field);\n var h = 1 - (e.clientY - o.top + document.body.scrollTop) / s;\n\n if (h > 1) h = 1;\n else if (h < 0) h = 0;\n\n _this.__color.h = h * 360;\n\n _this.setValue(_this.__color.toOriginal());\n\n return false;\n\n }\n\n };\n\n ColorController.superclass = Controller;\n\n common.extend(\n\n ColorController.prototype,\n Controller.prototype,\n\n {\n\n updateDisplay: function() {\n\n var i = interpret(this.getValue());\n\n if (i !== false) {\n\n var mismatch = false;\n\n // Check for mismatch on the interpreted value.\n\n common.each(Color.COMPONENTS, function(component) {\n if (!common.isUndefined(i[component]) &&\n !common.isUndefined(this.__color.__state[component]) &&\n i[component] !== this.__color.__state[component]) {\n mismatch = true;\n return {}; // break\n }\n }, this);\n\n // If nothing diverges, we keep our previous values\n // for statefulness, otherwise we recalculate fresh\n if (mismatch) {\n common.extend(this.__color.__state, i);\n }\n\n }\n\n common.extend(this.__temp.__state, this.__color.__state);\n\n this.__temp.a = 1;\n\n var flip = (this.__color.v < .5 || this.__color.s > .5) ? 255 : 0;\n var _flip = 255 - flip;\n\n common.extend(this.__field_knob.style, {\n marginLeft: 100 * this.__color.s - 7 + 'px',\n marginTop: 100 * (1 - this.__color.v) - 7 + 'px',\n backgroundColor: this.__temp.toString(),\n border: this.__field_knob_border + 'rgb(' + flip + ',' + flip + ',' + flip +')'\n });\n\n this.__hue_knob.style.marginTop = (1 - this.__color.h / 360) * 100 + 'px'\n\n this.__temp.s = 1;\n this.__temp.v = 1;\n\n linearGradient(this.__saturation_field, 'left', '#fff', this.__temp.toString());\n\n common.extend(this.__input.style, {\n backgroundColor: this.__input.value = this.__color.toString(),\n color: 'rgb(' + flip + ',' + flip + ',' + flip +')',\n textShadow: this.__input_textShadow + 'rgba(' + _flip + ',' + _flip + ',' + _flip +',.7)'\n });\n\n }\n\n }\n\n );\n \n var vendors = ['-moz-','-o-','-webkit-','-ms-',''];\n \n function linearGradient(elem, x, a, b) {\n elem.style.background = '';\n common.each(vendors, function(vendor) {\n elem.style.cssText += 'background: ' + vendor + 'linear-gradient('+x+', '+a+' 0%, ' + b + ' 100%); ';\n });\n }\n \n function hueGradient(elem) {\n elem.style.background = '';\n elem.style.cssText += 'background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);'\n elem.style.cssText += 'background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'\n elem.style.cssText += 'background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'\n elem.style.cssText += 'background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'\n elem.style.cssText += 'background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'\n }\n\n\n return ColorController;\n\n})(dat.controllers.Controller,\ndat.dom.dom,\ndat.color.Color = (function (interpret, math, toString, common) {\n\n var Color = function() {\n\n this.__state = interpret.apply(this, arguments);\n\n if (this.__state === false) {\n throw 'Failed to interpret color arguments';\n }\n\n this.__state.a = this.__state.a || 1;\n\n\n };\n\n Color.COMPONENTS = ['r','g','b','h','s','v','hex','a'];\n\n common.extend(Color.prototype, {\n\n toString: function() {\n return toString(this);\n },\n\n toOriginal: function() {\n return this.__state.conversion.write(this);\n }\n\n });\n\n defineRGBComponent(Color.prototype, 'r', 2);\n defineRGBComponent(Color.prototype, 'g', 1);\n defineRGBComponent(Color.prototype, 'b', 0);\n\n defineHSVComponent(Color.prototype, 'h');\n defineHSVComponent(Color.prototype, 's');\n defineHSVComponent(Color.prototype, 'v');\n\n Object.defineProperty(Color.prototype, 'a', {\n\n get: function() {\n return this.__state.a;\n },\n\n set: function(v) {\n this.__state.a = v;\n }\n\n });\n\n Object.defineProperty(Color.prototype, 'hex', {\n\n get: function() {\n\n if (!this.__state.space !== 'HEX') {\n this.__state.hex = math.rgb_to_hex(this.r, this.g, this.b);\n }\n\n return this.__state.hex;\n\n },\n\n set: function(v) {\n\n this.__state.space = 'HEX';\n this.__state.hex = v;\n\n }\n\n });\n\n function defineRGBComponent(target, component, componentHexIndex) {\n\n Object.defineProperty(target, component, {\n\n get: function() {\n\n if (this.__state.space === 'RGB') {\n return this.__state[component];\n }\n\n recalculateRGB(this, component, componentHexIndex);\n\n return this.__state[component];\n\n },\n\n set: function(v) {\n\n if (this.__state.space !== 'RGB') {\n recalculateRGB(this, component, componentHexIndex);\n this.__state.space = 'RGB';\n }\n\n this.__state[component] = v;\n\n }\n\n });\n\n }\n\n function defineHSVComponent(target, component) {\n\n Object.defineProperty(target, component, {\n\n get: function() {\n\n if (this.__state.space === 'HSV')\n return this.__state[component];\n\n recalculateHSV(this);\n\n return this.__state[component];\n\n },\n\n set: function(v) {\n\n if (this.__state.space !== 'HSV') {\n recalculateHSV(this);\n this.__state.space = 'HSV';\n }\n\n this.__state[component] = v;\n\n }\n\n });\n\n }\n\n function recalculateRGB(color, component, componentHexIndex) {\n\n if (color.__state.space === 'HEX') {\n\n color.__state[component] = math.component_from_hex(color.__state.hex, componentHexIndex);\n\n } else if (color.__state.space === 'HSV') {\n\n common.extend(color.__state, math.hsv_to_rgb(color.__state.h, color.__state.s, color.__state.v));\n\n } else {\n\n throw 'Corrupted color state';\n\n }\n\n }\n\n function recalculateHSV(color) {\n\n var result = math.rgb_to_hsv(color.r, color.g, color.b);\n\n common.extend(color.__state,\n {\n s: result.s,\n v: result.v\n }\n );\n\n if (!common.isNaN(result.h)) {\n color.__state.h = result.h;\n } else if (common.isUndefined(color.__state.h)) {\n color.__state.h = 0;\n }\n\n }\n\n return Color;\n\n})(dat.color.interpret,\ndat.color.math = (function () {\n\n var tmpComponent;\n\n return {\n\n hsv_to_rgb: function(h, s, v) {\n\n var hi = Math.floor(h / 60) % 6;\n\n var f = h / 60 - Math.floor(h / 60);\n var p = v * (1.0 - s);\n var q = v * (1.0 - (f * s));\n var t = v * (1.0 - ((1.0 - f) * s));\n var c = [\n [v, t, p],\n [q, v, p],\n [p, v, t],\n [p, q, v],\n [t, p, v],\n [v, p, q]\n ][hi];\n\n return {\n r: c[0] * 255,\n g: c[1] * 255,\n b: c[2] * 255\n };\n\n },\n\n rgb_to_hsv: function(r, g, b) {\n\n var min = Math.min(r, g, b),\n max = Math.max(r, g, b),\n delta = max - min,\n h, s;\n\n if (max != 0) {\n s = delta / max;\n } else {\n return {\n h: NaN,\n s: 0,\n v: 0\n };\n }\n\n if (r == max) {\n h = (g - b) / delta;\n } else if (g == max) {\n h = 2 + (b - r) / delta;\n } else {\n h = 4 + (r - g) / delta;\n }\n h /= 6;\n if (h < 0) {\n h += 1;\n }\n\n return {\n h: h * 360,\n s: s,\n v: max / 255\n };\n },\n\n rgb_to_hex: function(r, g, b) {\n var hex = this.hex_with_component(0, 2, r);\n hex = this.hex_with_component(hex, 1, g);\n hex = this.hex_with_component(hex, 0, b);\n return hex;\n },\n\n component_from_hex: function(hex, componentIndex) {\n return (hex >> (componentIndex * 8)) & 0xFF;\n },\n\n hex_with_component: function(hex, componentIndex, value) {\n return value << (tmpComponent = componentIndex * 8) | (hex & ~ (0xFF << tmpComponent));\n }\n\n }\n\n})(),\ndat.color.toString,\ndat.utils.common),\ndat.color.interpret,\ndat.utils.common),\ndat.utils.requestAnimationFrame = (function () {\n\n /**\n * requirejs version of Paul Irish's RequestAnimationFrame\n * http://paulirish.com/2011/requestanimationframe-for-smart-animating/\n */\n\n return window.webkitRequestAnimationFrame ||\n window.mozRequestAnimationFrame ||\n window.oRequestAnimationFrame ||\n window.msRequestAnimationFrame ||\n function(callback, element) {\n\n window.setTimeout(callback, 1000 / 60);\n\n };\n})(),\ndat.dom.CenteredDiv = (function (dom, common) {\n\n\n var CenteredDiv = function() {\n\n this.backgroundElement = document.createElement('div');\n common.extend(this.backgroundElement.style, {\n backgroundColor: 'rgba(0,0,0,0.8)',\n top: 0,\n left: 0,\n display: 'none',\n zIndex: '1000',\n opacity: 0,\n WebkitTransition: 'opacity 0.2s linear'\n });\n\n dom.makeFullscreen(this.backgroundElement);\n this.backgroundElement.style.position = 'fixed';\n\n this.domElement = document.createElement('div');\n common.extend(this.domElement.style, {\n position: 'fixed',\n display: 'none',\n zIndex: '1001',\n opacity: 0,\n WebkitTransition: '-webkit-transform 0.2s ease-out, opacity 0.2s linear'\n });\n\n\n document.body.appendChild(this.backgroundElement);\n document.body.appendChild(this.domElement);\n\n var _this = this;\n dom.bind(this.backgroundElement, 'click', function() {\n _this.hide();\n });\n\n\n };\n\n CenteredDiv.prototype.show = function() {\n\n var _this = this;\n \n\n\n this.backgroundElement.style.display = 'block';\n\n this.domElement.style.display = 'block';\n this.domElement.style.opacity = 0;\n// this.domElement.style.top = '52%';\n this.domElement.style.webkitTransform = 'scale(1.1)';\n\n this.layout();\n\n common.defer(function() {\n _this.backgroundElement.style.opacity = 1;\n _this.domElement.style.opacity = 1;\n _this.domElement.style.webkitTransform = 'scale(1)';\n });\n\n };\n\n CenteredDiv.prototype.hide = function() {\n\n var _this = this;\n\n var hide = function() {\n\n _this.domElement.style.display = 'none';\n _this.backgroundElement.style.display = 'none';\n\n dom.unbind(_this.domElement, 'webkitTransitionEnd', hide);\n dom.unbind(_this.domElement, 'transitionend', hide);\n dom.unbind(_this.domElement, 'oTransitionEnd', hide);\n\n };\n\n dom.bind(this.domElement, 'webkitTransitionEnd', hide);\n dom.bind(this.domElement, 'transitionend', hide);\n dom.bind(this.domElement, 'oTransitionEnd', hide);\n\n this.backgroundElement.style.opacity = 0;\n// this.domElement.style.top = '48%';\n this.domElement.style.opacity = 0;\n this.domElement.style.webkitTransform = 'scale(1.1)';\n\n };\n\n CenteredDiv.prototype.layout = function() {\n this.domElement.style.left = window.innerWidth/2 - dom.getWidth(this.domElement) / 2 + 'px';\n this.domElement.style.top = window.innerHeight/2 - dom.getHeight(this.domElement) / 2 + 'px';\n };\n \n function lockScroll(e) {\n console.log(e);\n }\n\n return CenteredDiv;\n\n})(dat.dom.dom,\ndat.utils.common),\ndat.dom.dom,\ndat.utils.common);\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/dat-gui/vendor/dat.gui.js\n// module id = 24\n// module chunks = 0","module.exports = __webpack_public_path__ + \"./assets/iridescent-ec82e7.bmp\";\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/assets/iridescent.bmp\n// module id = 25\n// module chunks = 0","module.exports = __webpack_public_path__ + \"./assets/wahoo-1bfe66.bmp\";\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/assets/wahoo.bmp\n// module id = 26\n// module chunks = 0","/**\n * @author alteredq / http://alteredqualia.com/\n *\n * Full-screen textured quad shader\n */\n\nmodule.exports = {\n uniforms: {\n \"tDiffuse\": { type: \"t\", value: null },\n \"opacity\": { type: \"f\", value: 1.0 }\n },\n vertexShader: [\n \"varying vec2 vUv;\",\n\n \"void main() {\",\n\n \"vUv = uv;\",\n \"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\",\n\n \"}\"\n ].join(\"\\n\"),\n fragmentShader: [\n \"uniform float opacity;\",\n\n \"uniform sampler2D tDiffuse;\",\n\n \"varying vec2 vUv;\",\n\n \"void main() {\",\n\n \"vec4 texel = texture2D( tDiffuse, vUv );\",\n \"gl_FragColor = opacity * texel;\",\n\n \"}\"\n ].join(\"\\n\")\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/three-copyshader/index.js\n// module id = 27\n// module chunks = 0","/**\n * @author alteredq / http://alteredqualia.com/\n */\n\nmodule.exports = function(THREE) {\n function ClearMaskPass() {\n if (!(this instanceof ClearMaskPass)) return new ClearMaskPass(scene, camera);\n this.enabled = true;\n };\n\n ClearMaskPass.prototype = {\n render: function ( renderer, writeBuffer, readBuffer, delta ) {\n var context = renderer.context;\n context.disable( context.STENCIL_TEST );\n }\n };\n\n return ClearMaskPass\n};\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/three-effectcomposer/lib/clearmaskpass.js\n// module id = 28\n// module chunks = 0","/**\n * @author alteredq / http://alteredqualia.com/\n */\n\nmodule.exports = function(THREE) {\n function MaskPass( scene, camera ) {\n if (!(this instanceof MaskPass)) return new MaskPass(scene, camera);\n\n this.scene = scene;\n this.camera = camera;\n\n this.enabled = true;\n this.clear = true;\n this.needsSwap = false;\n\n this.inverse = false;\n };\n\n MaskPass.prototype = {\n\n render: function ( renderer, writeBuffer, readBuffer, delta ) {\n\n var context = renderer.context;\n\n // don't update color or depth\n\n context.colorMask( false, false, false, false );\n context.depthMask( false );\n\n // set up stencil\n\n var writeValue, clearValue;\n\n if ( this.inverse ) {\n\n writeValue = 0;\n clearValue = 1;\n\n } else {\n\n writeValue = 1;\n clearValue = 0;\n\n }\n\n context.enable( context.STENCIL_TEST );\n context.stencilOp( context.REPLACE, context.REPLACE, context.REPLACE );\n context.stencilFunc( context.ALWAYS, writeValue, 0xffffffff );\n context.clearStencil( clearValue );\n\n // draw into the stencil buffer\n\n renderer.render( this.scene, this.camera, readBuffer, this.clear );\n renderer.render( this.scene, this.camera, writeBuffer, this.clear );\n\n // re-enable update of color and depth\n\n context.colorMask( true, true, true, true );\n context.depthMask( true );\n\n // only render where stencil is set to 1\n\n context.stencilFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1\n context.stencilOp( context.KEEP, context.KEEP, context.KEEP );\n\n }\n\n };\n\n return MaskPass\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/three-effectcomposer/lib/maskpass.js\n// module id = 29\n// module chunks = 0","/**\n * @author alteredq / http://alteredqualia.com/\n */\n\nmodule.exports = function(THREE) {\n function RenderPass( scene, camera, overrideMaterial, clearColor, clearAlpha ) {\n if (!(this instanceof RenderPass)) return new RenderPass(scene, camera, overrideMaterial, clearColor, clearAlpha);\n\n this.scene = scene;\n this.camera = camera;\n\n this.overrideMaterial = overrideMaterial;\n\n this.clearColor = clearColor;\n this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 1;\n\n this.oldClearColor = new THREE.Color();\n this.oldClearAlpha = 1;\n\n this.enabled = true;\n this.clear = true;\n this.needsSwap = false;\n\n };\n\n RenderPass.prototype = {\n\n render: function ( renderer, writeBuffer, readBuffer, delta ) {\n\n this.scene.overrideMaterial = this.overrideMaterial;\n\n if ( this.clearColor ) {\n\n this.oldClearColor.copy( renderer.getClearColor() );\n this.oldClearAlpha = renderer.getClearAlpha();\n\n renderer.setClearColor( this.clearColor, this.clearAlpha );\n\n }\n\n renderer.render( this.scene, this.camera, readBuffer, this.clear );\n\n if ( this.clearColor ) {\n\n renderer.setClearColor( this.oldClearColor, this.oldClearAlpha );\n\n }\n\n this.scene.overrideMaterial = null;\n\n }\n\n };\n\n return RenderPass;\n\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/three-effectcomposer/lib/renderpass.js\n// module id = 30\n// module chunks = 0","/**\n * @author alteredq / http://alteredqualia.com/\n */\n\nmodule.exports = function(THREE, EffectComposer) {\n function ShaderPass( shader, textureID ) {\n if (!(this instanceof ShaderPass)) return new ShaderPass(shader, textureID);\n\n this.textureID = ( textureID !== undefined ) ? textureID : \"tDiffuse\";\n\n this.uniforms = THREE.UniformsUtils.clone( shader.uniforms );\n\n this.material = new THREE.ShaderMaterial( {\n\n uniforms: this.uniforms,\n vertexShader: shader.vertexShader,\n fragmentShader: shader.fragmentShader\n\n } );\n\n this.renderToScreen = false;\n\n this.enabled = true;\n this.needsSwap = true;\n this.clear = false;\n\n };\n\n ShaderPass.prototype = {\n\n render: function ( renderer, writeBuffer, readBuffer, delta ) {\n\n if ( this.uniforms[ this.textureID ] ) {\n\n this.uniforms[ this.textureID ].value = readBuffer;\n\n }\n\n EffectComposer.quad.material = this.material;\n\n if ( this.renderToScreen ) {\n\n renderer.render( EffectComposer.scene, EffectComposer.camera );\n\n } else {\n\n renderer.render( EffectComposer.scene, EffectComposer.camera, writeBuffer, this.clear );\n\n }\n\n }\n\n };\n\n return ShaderPass;\n\n};\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/three-effectcomposer/lib/shaderpass.js\n// module id = 31\n// module chunks = 0","module.exports = \"uniform sampler2D tDiffuse;\\nuniform float u_amount;\\nuniform float sWidth;\\nuniform float sHeight;\\nvarying vec2 f_uv;\\n\\n\\n// Get the pixel in uv coordinates using an offset from the current position\\nvec2 getPixel(float x, float y) {\\n\\treturn f_uv + vec2(1.0/sWidth, 1.0/sHeight) * vec2(x, y);\\n}\\n\\n// Retrieves the color from the texture\\nvec4 getColor(vec2 pixel) {\\n\\tvec4 col = texture2D(tDiffuse, pixel);\\n\\treturn col;\\n}\\n\\nvoid main() {\\n\\t// Get colors for each pixel\\n\\tvec4 a = getColor(getPixel(-1.0, -1.0));\\n\\tvec4 b = getColor(getPixel(0.0, -1.0));\\n\\tvec4 c = getColor(getPixel(1.0, -1.0));\\n\\tvec4 d = getColor(getPixel(-1.0, 0.0));\\n\\tvec4 e = getColor(getPixel(0.0, 0.0));\\n\\tvec4 f = getColor(getPixel(1.0, 0.0));\\n\\tvec4 g = getColor(getPixel(-1.0, 1.0));\\n\\tvec4 h = getColor(getPixel(0.0, 1.0));\\n\\tvec4 i = getColor(getPixel(1.0, 1.0));\\n\\n\\t// Apply weighted average\\n\\tgl_FragColor = 0.1107* (a + c + g + i) + 0.1113* (b + d + h + f) + 0.1119 * e;\\n} \"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/glsl/gaussian-frag.glsl\n// module id = 32\n// module chunks = 0","module.exports = \"\\nuniform sampler2D tDiffuse;\\nuniform float u_amount;\\nvarying vec2 f_uv;\\n\\n// tDiffuse is a special uniform sampler that THREE.js will bind the previously rendered frame to\\n\\nvoid main() {\\n vec4 col = texture2D(tDiffuse, f_uv);\\n float gray = dot(col.rgb, vec3(0.299, 0.587, 0.114));\\n\\n col.rgb = vec3(gray, gray, gray) * (u_amount) + col.rgb * (1.0 - u_amount);\\n\\n gl_FragColor = col;\\n} \"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/glsl/grayscale-frag.glsl\n// module id = 33\n// module chunks = 0","module.exports = \"\\nuniform sampler2D tDiffuse;\\nuniform float u_amount;\\nvarying vec2 f_uv;\\n\\n// tDiffuse is a special uniform sampler that THREE.js will bind the previously rendered frame to\\nvoid main() {\\n vec4 col = texture2D(tDiffuse, f_uv);\\n col = vec4(1.0 - col.x, 1.0 - col.y, 1.0 - col.z, 1.0 - u_amount);\\n gl_FragColor = col;\\n} \"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/glsl/invert-frag.glsl\n// module id = 34\n// module chunks = 0","module.exports = \"\\nuniform sampler2D texture;\\nuniform int u_useTexture;\\nuniform vec3 u_albedo;\\nuniform vec3 u_ambient;\\nuniform vec3 u_lightPos;\\nuniform vec3 u_lightCol;\\nuniform float u_lightIntensity;\\nuniform vec3 u_camPos;\\n\\nvarying vec3 f_position;\\nvarying vec3 f_normal;\\nvarying vec2 f_uv;\\nvarying float noise;\\n\\n\\nvoid main() {\\n vec4 color = vec4(u_albedo, 1.0);\\n float d = clamp(dot(f_normal, normalize(u_camPos - f_position)), 0.0, 1.0);\\n\\n // Read from texture using relation to the view vector and a little bit of noise\\n if (u_useTexture == 1) {\\n color = texture2D(texture, vec2(f_uv.x - d*float(noise), f_uv.y - d*float(noise)));\\n }\\n\\n gl_FragColor = vec4(d * color.rgb * u_lightCol * u_lightIntensity + u_ambient, 1.0);\\n}\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/glsl/iridescent-frag.glsl\n// module id = 35\n// module chunks = 0","module.exports = \"\\nvarying vec2 f_uv;\\nvarying vec3 f_normal;\\nvarying vec3 f_position;\\nvarying float noise;\\n\\nfloat random(float a, float b, float c) {\\n return fract(sin(dot(vec3(a, b, c), vec3(12.9898, 78.233, 78.233)))*43758.5453);\\n}\\n\\nfloat lerp(float a, float b, float t) {\\n return a * (1.0 - t) + b * t;\\n}\\n\\nvec4 lerp(vec4 a, vec4 b, float t) {\\n return a * (1.0 - t) + b * t;\\n}\\n\\nfloat cerp(float a, float b, float t) {\\n float cos_t = (1.0 - cos(t*3.14159)) * 0.5;\\n return lerp(a, b, cos_t);\\n}\\n\\nfloat interpolateNoise(float x, float y, float z) {\\n float x0, y0, z0, x1, y1, z1;\\n \\n // Find the grid voxel that this point falls in\\n x0 = floor(x);\\n y0 = floor(y);\\n z0 = floor(z);\\n \\n x1 = x0 + 1.0;\\n y1 = y0 + 1.0;\\n z1 = z0 + 1.0;\\n \\n // Generate noise at each of the 8 points\\n float FUL, FUR, FLL, FLR, BUL, BUR, BLL, BLR;\\n \\n // front upper left\\n FUL = random(x0, y1, z1);\\n \\n // front upper right\\n FUR = random(x1, y1, z1);\\n \\n // front lower left\\n FLL = random(x0, y0, z1);\\n \\n // front lower right\\n FLR = random(x1, y0, z1);\\n \\n // back upper left\\n BUL = random(x0, y1, z0);\\n \\n // back upper right\\n BUR = random(x1, y1, z0);\\n \\n // back lower left\\n BLL = random(x0, y0, z0);\\n \\n // back lower right\\n BLR = random(x1, y0, z0);\\n \\n // Find the interpolate t values\\n float n0, n1, m0, m1, v;\\n float tx = fract(x - x0);\\n float ty = fract(y - y0);\\n float tz = fract(z - z0);\\n tx = (x - x0);\\n ty = (y - y0);\\n tz = (z - z0);\\n \\n // interpolate along x and y for back\\n n0 = cerp(BLL, BLR, tx);\\n n1 = cerp(BUL, BUR, tx);\\n m0 = cerp(n0, n1, ty);\\n \\n // interpolate along x and y for front\\n n0 = cerp(FLL, FLR, tx);\\n n1 = cerp(FUL, FUR, tx);\\n m1 = cerp(n0, n1, ty);\\n \\n // interpolate along z\\n v = cerp(m0, m1, tz);\\n \\n return v;\\n}\\n\\nfloat generateNoise(float x, float y, float z) {\\n float total = 0.0;\\n float persistence = 1.0 / 2.0;\\n int its = 0;\\n for (int i = 0; i < 32; i++) {\\n float freq = pow(2.0, float(i));\\n float ampl = pow(persistence, float(i));\\n total += interpolateNoise(freq*x, freq*y, freq*z)*ampl;\\n }\\n return total;\\n}\\n\\nvoid main() {\\n // Pass noise to the fragment shader\\n\\tnoise = generateNoise(position.x, position.y, position.z);\\n f_uv = uv;\\n f_normal = normal;\\n f_position = position;\\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\\n}\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/glsl/iridescent-vert.glsl\n// module id = 36\n// module chunks = 0","module.exports = \"\\nuniform sampler2D texture;\\nuniform int u_useTexture;\\nuniform vec3 u_albedo;\\nuniform vec3 u_ambient;\\nuniform vec3 u_lightPos;\\nuniform vec3 u_lightCol;\\nuniform float u_lightIntensity;\\n\\nvarying vec3 f_position;\\nvarying vec3 f_normal;\\nvarying vec2 f_uv;\\n\\nvoid main() {\\n vec4 color = vec4(u_albedo, 1.0);\\n \\n if (u_useTexture == 1) {\\n color = texture2D(texture, f_uv);\\n }\\n\\n float d = clamp(dot(f_normal, normalize(u_lightPos - f_position)), 0.0, 1.0);\\n\\n gl_FragColor = vec4(d * color.rgb * u_lightCol * u_lightIntensity + u_ambient, 1.0);\\n}\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/glsl/lambert-frag.glsl\n// module id = 37\n// module chunks = 0","module.exports = \"\\nvarying vec2 f_uv;\\nvarying vec3 f_normal;\\nvarying vec3 f_position;\\n\\n// uv, position, projectionMatrix, modelViewMatrix, normal\\nvoid main() {\\n f_uv = uv;\\n f_normal = normal;\\n f_position = position;\\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\\n}\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/glsl/lambert-vert.glsl\n// module id = 38\n// module chunks = 0","module.exports = \"uniform sampler2D tDiffuse;\\nuniform float u_amount;\\nvarying vec2 f_uv;\\n\\n// tDiffuse is a special uniform sampler that THREE.js will bind the previously rendered frame to\\nfloat random(float a, float b, float c) {\\n return fract(sin(dot(vec3(a, b, c), vec3(12.9898, 78.233, 78.233)))*43758.5453);\\n}\\n\\nvoid main() {\\n // Retrieve color and transform to gray scale\\n vec4 col = texture2D(tDiffuse, f_uv);\\n float gray = dot(col.rgb, vec3(0.299, 0.587, 0.114));\\n col.rgb = vec3(gray, gray, gray) * (u_amount) + col.rgb * (1.0 - u_amount);\\n\\n // Scale probability with of darkness\\n float prob = random(f_uv.x, f_uv.y, 1.0)*(1.0 - col.r*col.b*col.g) / 4.0; \\n\\n // Compare probability to darkness and shade black if dark enough, white otherwise\\n if (prob > col.r*col.b*col.g) {\\n \\tgl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); \\n }\\n else {\\n \\tgl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\\n }\\n \\n} \"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/glsl/pointilism-frag.glsl\n// module id = 39\n// module chunks = 0","module.exports = \"\\nuniform sampler2D tDiffuse;\\nuniform float u_amount;\\nuniform float sWidth;\\nuniform float sHeight;\\nvarying vec2 f_uv;\\n\\n\\nvec2 getPixel(float x, float y) {\\n\\treturn f_uv + vec2(1.0/sWidth, 1.0/sHeight) * vec2(x, y);\\n}\\n\\nvec4 getGreyscaleColor(vec2 pixel) {\\n\\tvec4 col = texture2D(tDiffuse, pixel);\\n\\tfloat gray = dot(col.rgb, vec3(0.299, 0.587, 0.114));\\n\\tcol.rgb = vec3(gray, gray, gray) * (u_amount) + col.rgb * (1.0 - u_amount);\\n\\treturn col;\\n}\\n\\nvoid main() {\\n\\t// Gets greyscale pixel from neighboring pixels\\n\\tvec4 a = getGreyscaleColor(getPixel(-1.0, -1.0));\\n\\tvec4 b = getGreyscaleColor(getPixel(0.0, -1.0));\\n\\tvec4 c = getGreyscaleColor(getPixel(1.0, -1.0));\\n\\tvec4 d = getGreyscaleColor(getPixel(-1.0, 0.0));\\n\\tvec4 e = getGreyscaleColor(getPixel(0.0, 0.0));\\n\\tvec4 f = getGreyscaleColor(getPixel(1.0, 0.0));\\n\\tvec4 g = getGreyscaleColor(getPixel(-1.0, 1.0));\\n\\tvec4 h = getGreyscaleColor(getPixel(0.0, 1.0));\\n\\tvec4 i = getGreyscaleColor(getPixel(1.0, 1.0));\\n\\n\\tfloat r = sqrt(pow(-a.r - 2.0*d.r - g.r + c.r + 2.0*f.r + i.r, 2.0) \\n\\t\\t+ pow(a.r + 2.0*b.r + c.r - g.r -2.0*h.r - i.r, 2.0));\\n\\tfloat gc = sqrt(pow(-a.g - 2.0*d.g - g.g + c.g + 2.0*f.g + i.g, 2.0) \\n\\t\\t+ pow(a.g + 2.0*b.g + c.g - g.g -2.0*h.g - i.g, 2.0));\\n\\tfloat bc = sqrt(pow(-a.b - 2.0*d.b - g.b + c.b + 2.0*f.b + i.b, 2.0) \\n\\t\\t+ pow(a.b + 2.0*b.b + c.b - g.b -2.0*h.b - i.b, 2.0));\\n gl_FragColor = vec4(r, gc, bc, 1.0);\\n} \"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/glsl/sobel-frag.glsl\n// module id = 40\n// module chunks = 0","module.exports = \"\\nuniform sampler2D texture;\\nuniform int u_useTexture;\\nuniform vec3 u_albedo;\\nuniform vec3 u_ambient;\\nuniform vec3 u_lightPos;\\nuniform vec3 u_lightCol;\\nuniform float u_lightIntensity;\\nuniform vec3 u_camPos;\\nuniform vec3 u_camDir;\\nvarying vec3 f_position;\\nvarying vec3 f_normal;\\nvarying vec2 f_uv;\\n\\nvoid main() {\\n vec4 color = vec4(u_albedo, 1.0);\\n \\n if (u_useTexture == 1) {\\n color = texture2D(texture, f_uv);\\n }\\n\\n float d = clamp(dot(f_normal, normalize(u_lightPos - f_position)), 0.0, 1.0);\\n vec3 finalColor = d * color.rgb * u_lightCol * u_lightIntensity + u_ambient;\\n \\tfinalColor.x = floor(finalColor.x*3.0)/3.0;\\n \\tfinalColor.y = floor(finalColor.y*3.0)/3.0;\\n \\tfinalColor.z = floor(finalColor.z*3.0)/3.0;\\n \\tvec3 view_vec = -normalize(u_camPos - f_position);\\n \\tif (abs(dot(f_normal, view_vec)) <= 0.4) {\\n \\t\\tfinalColor = vec3(0.0, 0.0, 0.0);\\n \\t}\\n gl_FragColor = vec4(finalColor, 1.0);\\n}\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/glsl/toon-frag.glsl\n// module id = 41\n// module chunks = 0","module.exports = \"\\nvarying vec2 f_uv;\\nvarying vec3 f_normal;\\nvarying vec3 f_position;\\n\\n// uv, position, projectionMatrix, modelViewMatrix, normal\\nvoid main() {\\n f_uv = uv;\\n f_normal = normal;\\n f_position = position;\\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\\n}\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/glsl/toon-vert.glsl\n// module id = 42\n// module chunks = 0","module.exports = \"\\nuniform sampler2D tDiffuse;\\nuniform float u_amount;\\nuniform float sWidth;\\nuniform float sHeight;\\nuniform vec3 u_color;\\nvarying vec2 f_uv;\\n\\n\\nvec2 getPixel(float x, float y) {\\n\\treturn f_uv + vec2(1.0/sWidth, 1.0/sHeight) * vec2(x, y);\\n}\\nfloat getDistance(vec2 pixel) {\\n\\treturn sqrt(pow(pixel.x - 0.5, 2.0) + pow(pixel.y - 0.5, 2.0));\\n}\\nvec4 getColor() {\\n\\tvec4 col = texture2D(tDiffuse, f_uv);\\n\\treturn col;\\n}\\nvec4 lerp(vec4 c1, vec4 c2, float t) {\\n\\treturn (1.0 - t)*c1 + t*c2;\\n}\\n// tDiffuse is a special uniform sampler that THREE.js will bind the previously rendered frame to\\nvoid main() {\\n gl_FragColor = lerp(getColor(), u_amount*vec4(u_color, 1), clamp(getDistance(getPixel(0.0, 0.0)), 0.0, 1.0));\\n\\n} \"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/glsl/vignette-frag.glsl\n// module id = 43\n// module chunks = 0","require('file-loader?name=[name].[ext]!../index.html');\n\nconst THREE = require('three');\nconst OrbitControls = require('three-orbit-controls')(THREE)\n\nimport Stats from 'stats-js'\nimport {objLoaded} from './mario'\nimport {setupGUI} from './setup'\n\nwindow.addEventListener('load', function() {\n var stats = new Stats();\n stats.setMode(1);\n stats.domElement.style.position = 'absolute';\n stats.domElement.style.left = '0px';\n stats.domElement.style.top = '0px';\n document.body.appendChild(stats.domElement);\n\n var scene = new THREE.Scene();\n var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );\n var renderer = new THREE.WebGLRenderer( { antialias: true } );\n renderer.setPixelRatio(window.devicePixelRatio);\n renderer.setSize(window.innerWidth, window.innerHeight);\n renderer.setClearColor(0x999999, 1.0);\n\n var controls = new OrbitControls(camera, renderer.domElement);\n controls.enableDamping = true;\n controls.enableZoom = true;\n controls.rotateSpeed = 0.3;\n controls.zoomSpeed = 1.0;\n controls.panSpeed = 2.0;\n\n document.body.appendChild(renderer.domElement);\n\n window.addEventListener('resize', function() {\n camera.aspect = window.innerWidth / window.innerHeight;\n camera.updateProjectionMatrix();\n renderer.setSize(window.innerWidth, window.innerHeight);\n });\n \n var mesh, shader, post;\n // this gets called when we set the shader\n function shaderSet(Shader, gui) {\n // create the shader and initialize its gui\n shader = new Shader(renderer, scene, camera);\n shader.initGUI(gui);\n\n // recreate the mesh with a new material\n if (mesh) scene.remove(mesh);\n objLoaded.then(function(geo) {\n mesh = new THREE.Mesh(geo, shader.material);\n scene.add(mesh);\n });\n }\n\n // this gets called when we set the postprocess shader\n function postProcessSet(Post, gui) {\n // create the shader and initialize its gui\n post = new Post(renderer, scene, camera);\n post.initGUI(gui);\n }\n\n setupGUI(shaderSet, postProcessSet);\n\n objLoaded.then(function(geo) {\n // point the camera to Mario on load\n camera.position.set(5, 10, 15);\n const center = geo.boundingSphere.center;\n camera.lookAt(center);\n controls.target.set(center.x, center.y, center.z);\n });\n\n (function tick() {\n controls.update();\n stats.begin();\n if (shader && shader.update) shader.update(); // perform any necessary updates\n if (post && post.update) post.update(); // perform any necessary updates\n if (post) post.render(); // render the scene\n stats.end();\n requestAnimationFrame(tick);\n })();\n});\n\n\n// WEBPACK FOOTER //\n// ./src/main.js"],"sourceRoot":""} \ No newline at end of file diff --git a/build/index.html b/build/index.html new file mode 100644 index 0000000..8bc7d8a --- /dev/null +++ b/build/index.html @@ -0,0 +1,19 @@ + + + + Shader Demos + + + + + + \ No newline at end of file diff --git a/src/assets/iridescent.bmp b/src/assets/iridescent.bmp new file mode 100644 index 0000000..2f399a0 Binary files /dev/null and b/src/assets/iridescent.bmp differ diff --git a/src/glsl/gaussian-frag.glsl b/src/glsl/gaussian-frag.glsl new file mode 100644 index 0000000..a346e4d --- /dev/null +++ b/src/glsl/gaussian-frag.glsl @@ -0,0 +1,33 @@ +uniform sampler2D tDiffuse; +uniform float u_amount; +uniform float sWidth; +uniform float sHeight; +varying vec2 f_uv; + + +// Get the pixel in uv coordinates using an offset from the current position +vec2 getPixel(float x, float y) { + return f_uv + vec2(1.0/sWidth, 1.0/sHeight) * vec2(x, y); +} + +// Retrieves the color from the texture +vec4 getColor(vec2 pixel) { + vec4 col = texture2D(tDiffuse, pixel); + return col; +} + +void main() { + // Get colors for each pixel + vec4 a = getColor(getPixel(-1.0, -1.0)); + vec4 b = getColor(getPixel(0.0, -1.0)); + vec4 c = getColor(getPixel(1.0, -1.0)); + vec4 d = getColor(getPixel(-1.0, 0.0)); + vec4 e = getColor(getPixel(0.0, 0.0)); + vec4 f = getColor(getPixel(1.0, 0.0)); + vec4 g = getColor(getPixel(-1.0, 1.0)); + vec4 h = getColor(getPixel(0.0, 1.0)); + vec4 i = getColor(getPixel(1.0, 1.0)); + + // Apply weighted average + gl_FragColor = 0.1107* (a + c + g + i) + 0.1113* (b + d + h + f) + 0.1119 * e; +} \ No newline at end of file diff --git a/src/glsl/invert-frag.glsl b/src/glsl/invert-frag.glsl new file mode 100644 index 0000000..b354de4 --- /dev/null +++ b/src/glsl/invert-frag.glsl @@ -0,0 +1,11 @@ + +uniform sampler2D tDiffuse; +uniform float u_amount; +varying vec2 f_uv; + +// tDiffuse is a special uniform sampler that THREE.js will bind the previously rendered frame to +void main() { + vec4 col = texture2D(tDiffuse, f_uv); + col = vec4(1.0 - col.x, 1.0 - col.y, 1.0 - col.z, 1.0 - u_amount); + gl_FragColor = col; +} \ No newline at end of file diff --git a/src/glsl/iridescent-frag.glsl b/src/glsl/iridescent-frag.glsl new file mode 100644 index 0000000..684f694 --- /dev/null +++ b/src/glsl/iridescent-frag.glsl @@ -0,0 +1,27 @@ + +uniform sampler2D texture; +uniform int u_useTexture; +uniform vec3 u_albedo; +uniform vec3 u_ambient; +uniform vec3 u_lightPos; +uniform vec3 u_lightCol; +uniform float u_lightIntensity; +uniform vec3 u_camPos; + +varying vec3 f_position; +varying vec3 f_normal; +varying vec2 f_uv; +varying float noise; + + +void main() { + vec4 color = vec4(u_albedo, 1.0); + float d = clamp(dot(f_normal, normalize(u_camPos - f_position)), 0.0, 1.0); + + // Read from texture using relation to the view vector and a little bit of noise + if (u_useTexture == 1) { + color = texture2D(texture, vec2(f_uv.x - d*float(noise), f_uv.y - d*float(noise))); + } + + gl_FragColor = vec4(d * color.rgb * u_lightCol * u_lightIntensity + u_ambient, 1.0); +} \ No newline at end of file diff --git a/src/glsl/iridescent-vert.glsl b/src/glsl/iridescent-vert.glsl new file mode 100644 index 0000000..c7dd2d4 --- /dev/null +++ b/src/glsl/iridescent-vert.glsl @@ -0,0 +1,107 @@ + +varying vec2 f_uv; +varying vec3 f_normal; +varying vec3 f_position; +varying float noise; + +float random(float a, float b, float c) { + return fract(sin(dot(vec3(a, b, c), vec3(12.9898, 78.233, 78.233)))*43758.5453); +} + +float lerp(float a, float b, float t) { + return a * (1.0 - t) + b * t; +} + +vec4 lerp(vec4 a, vec4 b, float t) { + return a * (1.0 - t) + b * t; +} + +float cerp(float a, float b, float t) { + float cos_t = (1.0 - cos(t*3.14159)) * 0.5; + return lerp(a, b, cos_t); +} + +float interpolateNoise(float x, float y, float z) { + float x0, y0, z0, x1, y1, z1; + + // Find the grid voxel that this point falls in + x0 = floor(x); + y0 = floor(y); + z0 = floor(z); + + x1 = x0 + 1.0; + y1 = y0 + 1.0; + z1 = z0 + 1.0; + + // Generate noise at each of the 8 points + float FUL, FUR, FLL, FLR, BUL, BUR, BLL, BLR; + + // front upper left + FUL = random(x0, y1, z1); + + // front upper right + FUR = random(x1, y1, z1); + + // front lower left + FLL = random(x0, y0, z1); + + // front lower right + FLR = random(x1, y0, z1); + + // back upper left + BUL = random(x0, y1, z0); + + // back upper right + BUR = random(x1, y1, z0); + + // back lower left + BLL = random(x0, y0, z0); + + // back lower right + BLR = random(x1, y0, z0); + + // Find the interpolate t values + float n0, n1, m0, m1, v; + float tx = fract(x - x0); + float ty = fract(y - y0); + float tz = fract(z - z0); + tx = (x - x0); + ty = (y - y0); + tz = (z - z0); + + // interpolate along x and y for back + n0 = cerp(BLL, BLR, tx); + n1 = cerp(BUL, BUR, tx); + m0 = cerp(n0, n1, ty); + + // interpolate along x and y for front + n0 = cerp(FLL, FLR, tx); + n1 = cerp(FUL, FUR, tx); + m1 = cerp(n0, n1, ty); + + // interpolate along z + v = cerp(m0, m1, tz); + + return v; +} + +float generateNoise(float x, float y, float z) { + float total = 0.0; + float persistence = 1.0 / 2.0; + int its = 0; + for (int i = 0; i < 32; i++) { + float freq = pow(2.0, float(i)); + float ampl = pow(persistence, float(i)); + total += interpolateNoise(freq*x, freq*y, freq*z)*ampl; + } + return total; +} + +void main() { + // Pass noise to the fragment shader + noise = generateNoise(position.x, position.y, position.z); + f_uv = uv; + f_normal = normal; + f_position = position; + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); +} \ No newline at end of file diff --git a/src/glsl/pass-vert.glsl b/src/glsl/pass-vert.glsl index 2166f7a..d9d2689 100644 --- a/src/glsl/pass-vert.glsl +++ b/src/glsl/pass-vert.glsl @@ -1,6 +1,5 @@ // we use this vertex shader for the post process steps. All we do is copy the uv value and set position appropriately - varying vec2 f_uv; void main() { f_uv = uv; diff --git a/src/glsl/pointilism-frag.glsl b/src/glsl/pointilism-frag.glsl new file mode 100644 index 0000000..409036c --- /dev/null +++ b/src/glsl/pointilism-frag.glsl @@ -0,0 +1,27 @@ +uniform sampler2D tDiffuse; +uniform float u_amount; +varying vec2 f_uv; + +// tDiffuse is a special uniform sampler that THREE.js will bind the previously rendered frame to +float random(float a, float b, float c) { + return fract(sin(dot(vec3(a, b, c), vec3(12.9898, 78.233, 78.233)))*43758.5453); +} + +void main() { + // Retrieve color and transform to gray scale + vec4 col = texture2D(tDiffuse, f_uv); + float gray = dot(col.rgb, vec3(0.299, 0.587, 0.114)); + col.rgb = vec3(gray, gray, gray) * (u_amount) + col.rgb * (1.0 - u_amount); + + // Scale probability with of darkness + float prob = random(f_uv.x, f_uv.y, 1.0)*(1.0 - col.r*col.b*col.g) / 4.0; + + // Compare probability to darkness and shade black if dark enough, white otherwise + if (prob > col.r*col.b*col.g) { + gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); + } + else { + gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); + } + +} \ No newline at end of file diff --git a/src/glsl/sobel-frag.glsl b/src/glsl/sobel-frag.glsl new file mode 100644 index 0000000..433592d --- /dev/null +++ b/src/glsl/sobel-frag.glsl @@ -0,0 +1,39 @@ + +uniform sampler2D tDiffuse; +uniform float u_amount; +uniform float sWidth; +uniform float sHeight; +varying vec2 f_uv; + + +vec2 getPixel(float x, float y) { + return f_uv + vec2(1.0/sWidth, 1.0/sHeight) * vec2(x, y); +} + +vec4 getGreyscaleColor(vec2 pixel) { + vec4 col = texture2D(tDiffuse, pixel); + float gray = dot(col.rgb, vec3(0.299, 0.587, 0.114)); + col.rgb = vec3(gray, gray, gray) * (u_amount) + col.rgb * (1.0 - u_amount); + return col; +} + +void main() { + // Gets greyscale pixel from neighboring pixels + vec4 a = getGreyscaleColor(getPixel(-1.0, -1.0)); + vec4 b = getGreyscaleColor(getPixel(0.0, -1.0)); + vec4 c = getGreyscaleColor(getPixel(1.0, -1.0)); + vec4 d = getGreyscaleColor(getPixel(-1.0, 0.0)); + vec4 e = getGreyscaleColor(getPixel(0.0, 0.0)); + vec4 f = getGreyscaleColor(getPixel(1.0, 0.0)); + vec4 g = getGreyscaleColor(getPixel(-1.0, 1.0)); + vec4 h = getGreyscaleColor(getPixel(0.0, 1.0)); + vec4 i = getGreyscaleColor(getPixel(1.0, 1.0)); + + float r = sqrt(pow(-a.r - 2.0*d.r - g.r + c.r + 2.0*f.r + i.r, 2.0) + + pow(a.r + 2.0*b.r + c.r - g.r -2.0*h.r - i.r, 2.0)); + float gc = sqrt(pow(-a.g - 2.0*d.g - g.g + c.g + 2.0*f.g + i.g, 2.0) + + pow(a.g + 2.0*b.g + c.g - g.g -2.0*h.g - i.g, 2.0)); + float bc = sqrt(pow(-a.b - 2.0*d.b - g.b + c.b + 2.0*f.b + i.b, 2.0) + + pow(a.b + 2.0*b.b + c.b - g.b -2.0*h.b - i.b, 2.0)); + gl_FragColor = vec4(r, gc, bc, 1.0); +} \ No newline at end of file diff --git a/src/glsl/toon-frag.glsl b/src/glsl/toon-frag.glsl new file mode 100644 index 0000000..c8a5377 --- /dev/null +++ b/src/glsl/toon-frag.glsl @@ -0,0 +1,32 @@ + +uniform sampler2D texture; +uniform int u_useTexture; +uniform vec3 u_albedo; +uniform vec3 u_ambient; +uniform vec3 u_lightPos; +uniform vec3 u_lightCol; +uniform float u_lightIntensity; +uniform vec3 u_camPos; +uniform vec3 u_camDir; +varying vec3 f_position; +varying vec3 f_normal; +varying vec2 f_uv; + +void main() { + vec4 color = vec4(u_albedo, 1.0); + + if (u_useTexture == 1) { + color = texture2D(texture, f_uv); + } + + float d = clamp(dot(f_normal, normalize(u_lightPos - f_position)), 0.0, 1.0); + vec3 finalColor = d * color.rgb * u_lightCol * u_lightIntensity + u_ambient; + finalColor.x = floor(finalColor.x*3.0)/3.0; + finalColor.y = floor(finalColor.y*3.0)/3.0; + finalColor.z = floor(finalColor.z*3.0)/3.0; + vec3 view_vec = -normalize(u_camPos - f_position); + if (abs(dot(f_normal, view_vec)) <= 0.4) { + finalColor = vec3(0.0, 0.0, 0.0); + } + gl_FragColor = vec4(finalColor, 1.0); +} \ No newline at end of file diff --git a/src/glsl/toon-vert.glsl b/src/glsl/toon-vert.glsl new file mode 100644 index 0000000..86e2661 --- /dev/null +++ b/src/glsl/toon-vert.glsl @@ -0,0 +1,12 @@ + +varying vec2 f_uv; +varying vec3 f_normal; +varying vec3 f_position; + +// uv, position, projectionMatrix, modelViewMatrix, normal +void main() { + f_uv = uv; + f_normal = normal; + f_position = position; + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); +} \ No newline at end of file diff --git a/src/glsl/vignette-frag.glsl b/src/glsl/vignette-frag.glsl new file mode 100644 index 0000000..1def44b --- /dev/null +++ b/src/glsl/vignette-frag.glsl @@ -0,0 +1,27 @@ + +uniform sampler2D tDiffuse; +uniform float u_amount; +uniform float sWidth; +uniform float sHeight; +uniform vec3 u_color; +varying vec2 f_uv; + + +vec2 getPixel(float x, float y) { + return f_uv + vec2(1.0/sWidth, 1.0/sHeight) * vec2(x, y); +} +float getDistance(vec2 pixel) { + return sqrt(pow(pixel.x - 0.5, 2.0) + pow(pixel.y - 0.5, 2.0)); +} +vec4 getColor() { + vec4 col = texture2D(tDiffuse, f_uv); + return col; +} +vec4 lerp(vec4 c1, vec4 c2, float t) { + return (1.0 - t)*c1 + t*c2; +} +// tDiffuse is a special uniform sampler that THREE.js will bind the previously rendered frame to +void main() { + gl_FragColor = lerp(getColor(), u_amount*vec4(u_color, 1), clamp(getDistance(getPixel(0.0, 0.0)), 0.0, 1.0)); + +} \ No newline at end of file diff --git a/src/iridescentmario.js b/src/iridescentmario.js new file mode 100644 index 0000000..1e8ddb0 --- /dev/null +++ b/src/iridescentmario.js @@ -0,0 +1,19 @@ + +// this file is just for convenience. it sets up loading the mario obj and texture + +const THREE = require('three'); +require('three-obj-loader')(THREE) + +export var textureLoaded = new Promise((resolve, reject) => { + (new THREE.TextureLoader()).load(require('./assets/iridescent.bmp'), function(texture) { + resolve(texture); + }); +}) + +export var objLoaded = new Promise((resolve, reject) => { + (new THREE.OBJLoader()).load(require('./assets/wahoo.obj'), function(obj) { + var geo = obj.children[0].geometry; + geo.computeBoundingSphere(); + resolve(geo); + }); +}) \ No newline at end of file diff --git a/src/mario.js b/src/mario.js index 38647ba..cc0c39c 100644 --- a/src/mario.js +++ b/src/mario.js @@ -1,13 +1,13 @@ // this file is just for convenience. it sets up loading the mario obj and texture - +// comment const THREE = require('three'); require('three-obj-loader')(THREE) export var textureLoaded = new Promise((resolve, reject) => { (new THREE.TextureLoader()).load(require('./assets/wahoo.bmp'), function(texture) { resolve(texture); - }) + }); }) export var objLoaded = new Promise((resolve, reject) => { diff --git a/src/post/gaussian.js b/src/post/gaussian.js new file mode 100644 index 0000000..275a764 --- /dev/null +++ b/src/post/gaussian.js @@ -0,0 +1,54 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + amount: 1 +} +var GaussianShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_amount: { + type: 'f', + value: options.amount + }, + sHeight: { + type: 'f', + value: screen.height + }, + sWidth: { + type: 'f', + value: screen.width + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/gaussian-frag.glsl') +}); + +export default function Gaussian(renderer, scene, camera) { + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + + // first render the scene normally and add that as the first pass + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + + // then take the rendered result and apply the GaussianShader + composer.addPass(GaussianShader); + + // set this to true on the shader for your last pass to write to the screen + GaussianShader.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'amount', 0, 1).onChange(function(val) { + GaussianShader.material.uniforms.u_amount.value = val; + }); + }, + + render: function() {; + composer.render(); + } + } +} \ No newline at end of file diff --git a/src/post/index.js b/src/post/index.js index 9c0d763..722c14c 100644 --- a/src/post/index.js +++ b/src/post/index.js @@ -15,4 +15,9 @@ export function None(renderer, scene, camera) { } // follow this syntax to make your shaders available to the GUI -export {default as Grayscale} from './grayscale' \ No newline at end of file +export {default as Grayscale} from './grayscale' +export {default as Invert} from './invert' +export {default as Sobel} from './sobel' +export {default as Vignette} from './vignette' +export {default as Gaussian} from './gaussian' +export {default as Pointilism} from './pointilism' \ No newline at end of file diff --git a/src/post/invert.js b/src/post/invert.js new file mode 100644 index 0000000..75c3f6a --- /dev/null +++ b/src/post/invert.js @@ -0,0 +1,52 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + amount: 1 +} +var t = new Date(); +var invertShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_amount: { + type: 'f', + value: options.amount + }, + time: { + type: 'f', + value: t.getTime() + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/invert-frag.glsl') +}); + +export default function invert(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + + // first render the scene normally and add that as the first pass + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + + // then take the rendered result and apply the GrayscaleShader + composer.addPass(invertShader); + + // set this to true on the shader for your last pass to write to the screen + invertShader.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'amount', 0, 1).onChange(function(val) { + invertShader.material.uniforms.u_amount.value = val; + }); + }, + + render: function() {; + composer.render(); + } + } +} \ No newline at end of file diff --git a/src/post/pointilism.js b/src/post/pointilism.js new file mode 100644 index 0000000..7473dfe --- /dev/null +++ b/src/post/pointilism.js @@ -0,0 +1,54 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + amount: 1 +} +var PointilismShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_amount: { + type: 'f', + value: options.amount + }, + sHeight: { + type: 'f', + value: screen.height + }, + sWidth: { + type: 'f', + value: screen.width + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/pointilism-frag.glsl') +}); + +export default function Pointilism(renderer, scene, camera) { + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + + // first render the scene normally and add that as the first pass + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + + // then take the rendered result and apply the PointilismShader + composer.addPass(PointilismShader); + + // set this to true on the shader for your last pass to write to the screen + PointilismShader.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'amount', 0, 1).onChange(function(val) { + PointilismShader.material.uniforms.u_amount.value = val; + }); + }, + + render: function() {; + composer.render(); + } + } +} \ No newline at end of file diff --git a/src/post/sobel.js b/src/post/sobel.js new file mode 100644 index 0000000..650905d --- /dev/null +++ b/src/post/sobel.js @@ -0,0 +1,54 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + amount: 1 +} +var SobelShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_amount: { + type: 'f', + value: options.amount + }, + sHeight: { + type: 'f', + value: screen.height + }, + sWidth: { + type: 'f', + value: screen.width + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/sobel-frag.glsl') +}); + +export default function Grayscale(renderer, scene, camera) { + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + + // first render the scene normally and add that as the first pass + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + + // then take the rendered result and apply the SobelShader + composer.addPass(SobelShader); + + // set this to true on the shader for your last pass to write to the screen + SobelShader.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'amount', 0, 1).onChange(function(val) { + SobelShader.material.uniforms.u_amount.value = val; + }); + }, + + render: function() {; + composer.render(); + } + } +} \ No newline at end of file diff --git a/src/post/vignette.js b/src/post/vignette.js new file mode 100644 index 0000000..f402d1e --- /dev/null +++ b/src/post/vignette.js @@ -0,0 +1,56 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + amount: 1, + color: '#ffffff' +} + +var VignetteShaders = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_amount: { + type: 'f', + value: options.amount + }, + u_color: { + type: 'v3', + value: new THREE.Color(options.lightColor) + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/vignette-frag.glsl') +}); + +export default function Vignette(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + + // first render the scene normally and add that as the first pass + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + + // then take the rendered result and apply the VignetteShaders + composer.addPass(VignetteShaders); + + // set this to true on the shader for your last pass to write to the screen + VignetteShaders.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'amount', 0, 1).onChange(function(val) { + VignetteShaders.material.uniforms.u_amount.value = val; + }); + gui.addColor(options, 'color').onChange(function(val) { + VignetteShaders.material.uniforms.u_color.value = new THREE.Color(val); + }); + }, + + render: function() {; + composer.render(); + } + } +} \ No newline at end of file diff --git a/src/shaders/index.js b/src/shaders/index.js index e5b85c1..0987a37 100644 --- a/src/shaders/index.js +++ b/src/shaders/index.js @@ -1,4 +1,6 @@ // This file exports available shaders to the GUI. // follow this syntax to make your shaders available to the GUI -export {default as Lambert} from './lambert' \ No newline at end of file +export {default as Lambert} from './lambert' +export {default as Toon} from './toon' +export {default as Iridescent} from './iridescent' \ No newline at end of file diff --git a/src/shaders/iridescent.js b/src/shaders/iridescent.js new file mode 100644 index 0000000..21214af --- /dev/null +++ b/src/shaders/iridescent.js @@ -0,0 +1,80 @@ + +const THREE = require('three'); +import {textureLoaded} from '../iridescentmario' + +// options for lambert shader +var options = { + lightColor: '#ffffff', + lightIntensity: 2, + albedo: '#dddddd', + ambient: '#111111', + useTexture: true +} + +export default function(renderer, scene, camera) { + const Shader = { + initGUI: function(gui) { + gui.addColor(options, 'lightColor').onChange(function(val) { + Shader.material.uniforms.u_lightCol.value = new THREE.Color(val); + }); + gui.add(options, 'lightIntensity').onChange(function(val) { + Shader.material.uniforms.u_lightIntensity.value = val; + }); + gui.addColor(options, 'albedo').onChange(function(val) { + Shader.material.uniforms.u_albedo.value = new THREE.Color(val); + }); + gui.addColor(options, 'ambient').onChange(function(val) { + Shader.material.uniforms.u_ambient.value = new THREE.Color(val); + }); + gui.add(options, 'useTexture').onChange(function(val) { + Shader.material.uniforms.u_useTexture.value = val; + }); + }, + + material: new THREE.ShaderMaterial({ + uniforms: { + texture: { + type: "t", + value: null + }, + u_useTexture: { + type: 'i', + value: options.useTexture + }, + u_albedo: { + type: 'v3', + value: new THREE.Color(options.albedo) + }, + u_ambient: { + type: 'v3', + value: new THREE.Color(options.ambient) + }, + u_lightPos: { + type: 'v3', + value: new THREE.Vector3(30, 50, 40) + }, + u_lightCol: { + type: 'v3', + value: new THREE.Color(options.lightColor) + }, + u_lightIntensity: { + type: 'f', + value: options.lightIntensity + }, + u_camPos: { + type: 'v3', + value: camera.position + } + }, + vertexShader: require('../glsl/iridescent-vert.glsl'), + fragmentShader: require('../glsl/iridescent-frag.glsl') + }) + } + + // once the Mario texture loads, bind it to the material + textureLoaded.then(function(texture) { + Shader.material.uniforms.texture.value = texture; + }); + + return Shader; +} \ No newline at end of file diff --git a/src/shaders/toon.js b/src/shaders/toon.js new file mode 100644 index 0000000..e99f8eb --- /dev/null +++ b/src/shaders/toon.js @@ -0,0 +1,87 @@ + +const THREE = require('three'); +import {textureLoaded} from '../mario' + +// options for lambert shader +var options = { + lightColor: '#ffffff', + lightIntensity: 2, + albedo: '#dddddd', + ambient: '#111111', + useTexture: true +} + +export default function(renderer, scene, camera) { + var pLocal = new THREE.Vector3(0, 0, -1); + var pWorld = pLocal.applyMatrix4( camera.matrixWorld ); + var dir = pWorld.sub( camera.position ).normalize(); + const Shader = { + initGUI: function(gui) { + gui.addColor(options, 'lightColor').onChange(function(val) { + Shader.material.uniforms.u_lightCol.value = new THREE.Color(val); + }); + gui.add(options, 'lightIntensity').onChange(function(val) { + Shader.material.uniforms.u_lightIntensity.value = val; + }); + gui.addColor(options, 'albedo').onChange(function(val) { + Shader.material.uniforms.u_albedo.value = new THREE.Color(val); + }); + gui.addColor(options, 'ambient').onChange(function(val) { + Shader.material.uniforms.u_ambient.value = new THREE.Color(val); + }); + gui.add(options, 'useTexture').onChange(function(val) { + Shader.material.uniforms.u_useTexture.value = val; + }); + }, + + material: new THREE.ShaderMaterial({ + uniforms: { + texture: { + type: "t", + value: null + }, + u_useTexture: { + type: 'i', + value: options.useTexture + }, + u_albedo: { + type: 'v3', + value: new THREE.Color(options.albedo) + }, + u_ambient: { + type: 'v3', + value: new THREE.Color(options.ambient) + }, + u_lightPos: { + type: 'v3', + value: new THREE.Vector3(30, 50, 40) + }, + u_lightCol: { + type: 'v3', + value: new THREE.Color(options.lightColor) + }, + u_lightIntensity: { + type: 'f', + value: options.lightIntensity + }, + u_camPos: { + type: 'v3', + value: camera.position + }, + u_camDir: { + type: 'v3', + value: dir + } + }, + vertexShader: require('../glsl/toon-vert.glsl'), + fragmentShader: require('../glsl/toon-frag.glsl') + }) + } + + // once the Mario texture loads, bind it to the material + textureLoaded.then(function(texture) { + Shader.material.uniforms.texture.value = texture; + }); + + return Shader; +} \ No newline at end of file